package com.xbongbong.paas.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.call.CallCenterService;
import com.xbongbong.paas.call.util.CallCenterUtil;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.MenuTypeEnum;
import com.xbongbong.paas.enums.PlatFormEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.help.ProFormHelp;
import com.xbongbong.paas.log.constant.CrmLogMemoConstant;
import com.xbongbong.paas.manager.feign.AliyuncallCenterFeignClient;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.pojo.CallLogExplainPojo;
import com.xbongbong.paas.pojo.SmsSpacePojo;
import com.xbongbong.paas.pojo.dto.AddCommunicateDTO;
import com.xbongbong.paas.pojo.dto.AliyunCallGetCompanyReqDTO;
import com.xbongbong.paas.pojo.dto.AliyunCallTimeFilterResultReqDTO;
import com.xbongbong.paas.pojo.dto.AutoCommunicateDTO;
import com.xbongbong.paas.pojo.dto.CallAppFiltersDTO;
import com.xbongbong.paas.pojo.dto.CallCallLogSaveDTO;
import com.xbongbong.paas.pojo.dto.CallCenterAccountUserInfoDTO;
import com.xbongbong.paas.pojo.dto.CallCenterFindRefDTO;
import com.xbongbong.paas.pojo.dto.CallCenterLoginDTO;
import com.xbongbong.paas.pojo.dto.CallCenterModuleDTO;
import com.xbongbong.paas.pojo.dto.CallCommunicateDTO;
import com.xbongbong.paas.pojo.dto.CallCustomerDisturbDTO;
import com.xbongbong.paas.pojo.dto.CallFindRefDTO;
import com.xbongbong.paas.pojo.dto.CallMobileCallDTO;
import com.xbongbong.paas.pojo.dto.CallMobileCodeSendDTO;
import com.xbongbong.paas.pojo.dto.CallMobileCodeVerifyDTO;
import com.xbongbong.paas.pojo.dto.CallSyncDepartmentDTO;
import com.xbongbong.paas.pojo.dto.CallTokenRefreshDTO;
import com.xbongbong.paas.pojo.dto.CallUpdateModuleDTO;
import com.xbongbong.paas.pojo.dto.GetSysVisibleDTO;
import com.xbongbong.paas.pojo.dto.IsActiveAliyunCallDTO;
import com.xbongbong.paas.pojo.dto.UserInfoDTO;
import com.xbongbong.paas.pojo.vo.AddCommunicateVO;
import com.xbongbong.paas.pojo.vo.AutoCommunicateVO;
import com.xbongbong.paas.pojo.vo.CallAppFiltersVO;
import com.xbongbong.paas.pojo.vo.CallCenterAccountGetByMobileVO;
import com.xbongbong.paas.pojo.vo.CallCenterAccountUserInfoVO;
import com.xbongbong.paas.pojo.vo.CallCenterConfigVO;
import com.xbongbong.paas.pojo.vo.CallCenterLoginVO;
import com.xbongbong.paas.pojo.vo.CallCenterModuleVO;
import com.xbongbong.paas.pojo.vo.CallCenterOrgGetByCorpIdVO;
import com.xbongbong.paas.pojo.vo.CallCustomerDisturbVO;
import com.xbongbong.paas.pojo.vo.CallFindRefVO;
import com.xbongbong.paas.pojo.vo.CallMobileCallVO;
import com.xbongbong.paas.pojo.vo.CallMobileCodeSendVO;
import com.xbongbong.paas.pojo.vo.CallMobileCodeVerifyVO;
import com.xbongbong.paas.pojo.vo.CallSyncDepartmentVO;
import com.xbongbong.paas.pojo.vo.CallTokenRefreshVO;
import com.xbongbong.paas.pojo.vo.CallUpdateModuleVO;
import com.xbongbong.paas.pojo.vo.DuYanAccountVO;
import com.xbongbong.paas.pojo.vo.DuYanCallLogVO;
import com.xbongbong.paas.pojo.vo.DuYanOrganizationVO;
import com.xbongbong.paas.pojo.vo.DuYanTeamVO;
import com.xbongbong.paas.pojo.vo.GetSysVisibleVO;
import com.xbongbong.paas.pojo.vo.IsActiveAliyunCallVO;
import com.xbongbong.paas.pojo.vo.TimeFilterResultVO;
import com.xbongbong.paas.pojo.vo.UserInfoVO;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisConstant;
import com.xbongbong.paas.service.CallCenterAccountService;
import com.xbongbong.paas.service.CallCenterCallLogService;
import com.xbongbong.paas.service.CallCenterCommonService;
import com.xbongbong.paas.service.CallCenterConfigService;
import com.xbongbong.paas.service.CallCenterOrganizationService;
import com.xbongbong.paas.service.CallCenterTeamService;
import com.xbongbong.paas.service.DepartmentService;
import com.xbongbong.paas.service.DuYanHttpService;
import com.xbongbong.paas.service.PaasAppService;
import com.xbongbong.paas.service.PaasFormService;
import com.xbongbong.paas.service.SMSSpaceService;
import com.xbongbong.paas.service.UserService;
import com.xbongbong.paas.service.aliyun.CloudCodeChartEnum;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.paas.toolbox.wrap.XbbResponse;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.paas.util.FormDataUtil;
import com.xbongbong.pro.applist.pojo.SelectOptionPojo;
import com.xbongbong.pro.applist.pojo.SelectPojo;
import com.xbongbong.pro.config.ProBaseConfig;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.enums.CallCenterTypeEnum;
import com.xbongbong.pro.enums.ErrorCodeEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.TimeTypeEnum;
import com.xbongbong.pro.enums.errorcodes.CallCenterErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.ClueErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.DuYanErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.XbbCallErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainDTO;
import com.xbongbong.pro.menu.pojo.vo.AppMenuListVO;
import com.xbongbong.pro.menu.pojo.vo.ControlCenterMenuVO;
import com.xbongbong.pro.menu.pojo.vo.PaasAppMenuVO;
import com.xbongbong.pro.service.toolbox.statistic.help.FiscalYearHelp;
import com.xbongbong.pro.statistic.pojo.FiscalYearTimePojo;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.constant.UserConstant;
import com.xbongbong.saas.constant.callcenter.CallCenterConstant;
import com.xbongbong.saas.constant.callcenter.CallCenterMemoConstant;
import com.xbongbong.saas.constant.callcenter.DuYanConstant;
import com.xbongbong.saas.domain.entity.CallCenterAccountEntity;
import com.xbongbong.saas.domain.entity.CallCenterCallLogEntity;
import com.xbongbong.saas.domain.entity.CallCenterOrganizationEntity;
import com.xbongbong.saas.domain.entity.CallCenterTeamEntity;
import com.xbongbong.saas.domain.entity.ext.ClueEntityExt;
import com.xbongbong.saas.domain.entity.ext.ContactEntityExt;
import com.xbongbong.saas.domain.entity.ext.CustomerEntityExt;
import com.xbongbong.saas.enums.CallLogResultEnum;
import com.xbongbong.saas.enums.CallLogTypeEnum;
import com.xbongbong.saas.enums.ClueRuleSettingEnum;
import com.xbongbong.saas.enums.RuleSettingEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ClueEnum;
import com.xbongbong.saas.enums.business.ContactEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.model.CallCenterAccountModel;
import com.xbongbong.saas.model.CallCenterOrganizationModel;
import com.xbongbong.saas.model.CallCenterTeamModel;
import com.xbongbong.saas.model.ClueModel;
import com.xbongbong.saas.model.ContactModel;
import com.xbongbong.saas.model.CustomerModel;
import com.xbongbong.saas.service.CustomerCommunicateService;
import com.xbongbong.saas.service.ScoreCalculateService;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.sys.domain.entity.CompanyEntity;
import com.xbongbong.sys.domain.entity.DepartmentEntity;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.enums.RoleEnum;
import com.xbongbong.sys.model.CompanyModel;
import com.xbongbong.sys.model.UserModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;

//import com.xbongbong.saas.service.toolbox.help.CommonHelp;

/**
 * @author youli.chen
 * @version v1.0
 * @description: 话务中心通用 业务层接口实现类
 * @date 2019/2/12 17:20
 * @since v1.0
 */
@Service("callCenterCommonService")
public class CallCenterCommonServiceImpl implements CallCenterCommonService {

    private static final Logger LOG = LoggerFactory.getLogger(CallCenterCommonServiceImpl.class);

    @Resource
    private UserModel userModel;
    @Resource
    private CallCenterAccountService callCenterAccountService;
    @Resource
    private CallCenterAccountModel callCenterAccountModel;
    @Resource
    private CallCenterOrganizationModel callCenterOrganizationModel;
    @Resource
    private CallCenterConfigService callCenterConfigService;
    @Resource
    private CallCenterOrganizationService callCenterOrganizationService;
    @Resource
    private DuYanHttpService duYanHttpService;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private CustomerModel customerModel;
    @Resource
    private ContactModel contactModel;
    @Resource
    private CustomerCommunicateService customerCommunicateService;
    @Resource
    private CallCenterTeamService callCenterTeamService;
    @Resource
    private CallCenterTeamModel callCenterTeamModel;
    @Resource
    private DepartmentService departmentService;
    @Resource
    private PaasAppService paasAppService;
    @Resource
    private PaasFormService paasFormService;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private ClueModel clueModel;
    @Resource
    private ScoreCalculateService scoreCalculateService;
    @Resource
    private ProFormHelp proFormHelp;
    @Resource
    private AliyuncallCenterFeignClient aliyuncallCenterFeignClient;
    @Resource
    private CompanyModel companyModel;
    @Resource
    private ProBaseConfig proBaseConfig;
    @Resource
    private CallCenterCallLogService callCenterCallLogService;
    @Resource
    private CallCenterService callCenterService;
    @Resource
    private UserService userService;

    /**
     * 校验是否为话务中心模块
     *
     * @param moduleType 微应用模块类型，参考CallCenterTypeEnum
     * @return boolean false：话务中心模块
     * @author youli.chen
     * @version v1.0
     * @since v1.0
     */
    @Override
    public boolean notCallCenterModule(Integer moduleType) throws XbbException {
        return CallCenterUtil.notCallCenterModule(moduleType);
    }

    /**
     * web端
     * 校验当前用户对应的公司是否开启呼叫中心并且是坐席用户(对应的呼叫中心功能模块是否开放,坐席用户开放模块)
     * 获取当前开启的呼叫平台对应的模块权限
     * @return 开通了呼叫中心并且是坐席：true 没有开通呼叫中心或是非坐席：false
     * @param corpid 公司id
     * @param userId 用户ID
     * @throws XbbException 业务异常
     * @author youli.chen
     * @version v1.0
     * @since v1.0
     */
    @Override
    public boolean isOpenCallAndAgent(String corpid, String userId) throws XbbException {
        return callCenterService.isOpenCallAndAgent(corpid, userId);
    }


    /**
     * 移动端
     * 校验当前用户对应的公司是否开启呼叫中心并且是坐席用户(对应的呼叫中心功能模块是否开放,坐席用户开放模块)
     * 获取当前开启的呼叫平台对应的模块权限
     * @return 开通了呼叫中心并且是坐席：true 没有开通呼叫中心或是非坐席：false
     * @param corpid 公司id
     * @param userId 用户ID
     * @throws XbbException 业务异常
     * @author youli.chen
     * @version v1.0
     * @since v1.0
     */
    @Override
    public boolean isOpenCallDingTalk(String corpid, String userId) throws XbbException {
        return callCenterService.isOpenCallDingTalk(corpid, userId);
    }

    /**
     * 校验手机号是否正确
     *
     * @param phoneNum 手机号码（提前校验不为空）
     * @return boolean 错误号码格式：true 正确号码格式：false
     * @author youli.chen
     * @version v1.0
     * @since v1.0
     */
    @Override
    public boolean isWrongMobilePhoneNum(String phoneNum) throws XbbException {
        return phoneNum.length() != UserConstant.MOBILE_PHONE_NUM_COMMON_LENGTH
                || !phoneNum.startsWith(UserConstant.MOBILE_PHONE_NUM_COMMON_START_WITH);
    }

    /**
     * 格式化手机号，取能够用于查询的位数
     *
     * @param phoneNum 用于查询的通话号码
     * @return Object 对象（客户或联系人）
     * @author youli.chen
     * @version v1.0
     * @since v1.0
     */
    private String formatPhoneNum(String phoneNum) {
        boolean isCommonMobilePhone = (phoneNum.length() == UserConstant.MOBILE_PHONE_NUM_COMMON_LENGTH &&
                phoneNum.startsWith(UserConstant.MOBILE_PHONE_NUM_COMMON_START_WITH));
        if (phoneNum.length() <= UserConstant.PHONE_NUM_LENGTH || isCommonMobilePhone) {
            // 少于9位的号码 或 正常的"1"开头的11位手机号 直接查询
            return phoneNum;
        } else if (phoneNum.length() == UserConstant.MOBILE_PHONE_NUM_NATIONAL_LENGTH &&
                phoneNum.startsWith(UserConstant.MOBILE_PHONE_NUM_CN_START_WITH)) {
            // 13位的带"86"的国内号码
            return phoneNum.substring(2, phoneNum.length());
        } else {
            return phoneNum;
        }
    }

    /**
     * 获取话务中心平台管理员的token
     *
     * @param corpid     公司id
     * @param moduleType 第三方话务平台，参考CallCenterTypeEnum
     * @param accountId  员工的话务中心账户
     * @return token 登录验证
     * @throws XbbException 业务异常
     * @author youli.chen
     * @version v1.0
     * @since v1.0
     */
    @Override
    public String getAdminToken(String corpid, Integer moduleType, String accountId) throws XbbException {
        String apiKey = callCenterOrganizationService.getApiKey(corpid, moduleType);
        if (Objects.equals(moduleType, CallCenterTypeEnum.CALL_CENTER_DU_YAN.getCode())) {
            String token = duYanHttpService.adminLogin(apiKey, accountId);
            if (StringUtil.isEmpty(token)) {
                throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301064);
            }
            return token;
        } else {
            return null;
        }
    }

    /**
     * 用户一键登录使用的token或提醒用户进行注册
     *
     * @param callCenterLoginDTO 用户一键登录使用的token或提醒用户进行注册入参
     * @return CallCenterLoginVO
     * @throws XbbException 业务异常
     */
    @Override
    public XbbResponse<CallCenterLoginVO> login(CallCenterLoginDTO callCenterLoginDTO) throws XbbException {
        // 登录用户
        UserEntity logUser = userModel.getByKey(callCenterLoginDTO.getUserId(), callCenterLoginDTO.getCorpid());
        if (logUser == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100004);
        }
        CallCenterLoginVO callCenterLoginVO = new CallCenterLoginVO();
        Integer moduleType = callCenterLoginDTO.getModuleType();
        if (notCallCenterModule(moduleType)) {
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301029);
        }
        CallCenterAccountUserInfoDTO userInfoDTO = new CallCenterAccountUserInfoDTO();
        BeanUtils.copyProperties(callCenterLoginDTO, userInfoDTO);
        CallCenterAccountUserInfoVO callCenterAccountUserInfoVO = callCenterAccountService.getByXbbUserInfo(userInfoDTO);
        if (callCenterAccountUserInfoVO != null) {
            if (callCenterAccountUserInfoVO.getIsAgent() == 0) {
                if (callCenterAccountUserInfoVO.getIsAdmin() == 1) {
                    // 不是坐席但是是管理员
                    try {
                        initCallCenterAccountInfo(callCenterLoginVO, callCenterAccountUserInfoVO);
                    } catch (XbbException e) {
                        LOG.error(e.getMessage());
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018);
                    }
                } else {
                    // 既不是坐席又不是管理员，不需要看到话务中心
                    callCenterLoginVO.setCode(CallCenterErrorCodeEnum.API_ERROR_301002.getCode());
                    callCenterLoginVO.setMsg(CallCenterErrorCodeEnum.API_ERROR_301002.getMsg());
                }
            } else {
                // 销帮帮呼叫中心跳过手机号验证 youli.chen
                if (moduleType.equals(CallCenterTypeEnum.CALL_CENTER_DU_YAN.getCode())) {
                    checkDuYan(logUser, moduleType, callCenterAccountUserInfoVO, callCenterLoginDTO.getCorpid());
                }
                initCallCenterAccountInfo(callCenterLoginVO, callCenterAccountUserInfoVO);
            }
        }
        return new XbbResponse<>(callCenterLoginVO);
    }

    /**
     * 刷新token(用户一键登录使用的token或提醒用户进行注册)
     *
     * @param callTokenRefreshDTO 刷新token(用户一键登录使用的token或提醒用户进行注册)入参
     * @return CallTokenRefreshVO
     * @throws XbbException
     */
    @Override
    public XbbResponse<CallTokenRefreshVO> tokenRefresh(CallTokenRefreshDTO callTokenRefreshDTO) throws XbbException {
        // 登录用户
        UserEntity logUser = userModel.getByKey(callTokenRefreshDTO.getUserId(), callTokenRefreshDTO.getCorpid());
        if (logUser == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100004);
        }
        CallTokenRefreshVO callTokenRefreshVO = new CallTokenRefreshVO();
        Integer moduleType = callTokenRefreshDTO.getModuleType();
        if (notCallCenterModule(moduleType)) {
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301029);
        }
        if (moduleType != CallCenterTypeEnum.CALL_CENTER_DU_YAN.getCode()) {
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301065);
        }
        CallCenterAccountUserInfoDTO userInfoDTO = new CallCenterAccountUserInfoDTO();
        BeanUtils.copyProperties(callTokenRefreshDTO, userInfoDTO);
        CallCenterAccountUserInfoVO callCenterAccountUserInfoVO = callCenterAccountService.getByXbbUserInfo(userInfoDTO);
        if (callCenterAccountUserInfoVO == null || Objects.equals(callCenterAccountUserInfoVO.getIsAgent(), 0)) {
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301002);
        } else if (StringUtil.isEmpty(callCenterAccountUserInfoVO.getMobile())) {
            // TODO 后期和前端联调时确定一下这个mobile参数有没有用，考虑去掉
            if (StringUtil.isNotEmpty(logUser.getMobile())) {
                callTokenRefreshVO.setMobile(logUser.getMobile());
            }
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301003);
        } else {
            if (Objects.equals(callCenterAccountUserInfoVO.getIsMobileVerified(), 0)) {
                // 未验证手机号，等于没注册
                if (StringUtil.isNotEmpty(callCenterAccountUserInfoVO.getMobile())) {
                    callTokenRefreshVO.setMobile(callCenterAccountUserInfoVO.getMobile());
                } else if (StringUtil.isNotEmpty(logUser.getMobile())) {
                    callTokenRefreshVO.setMobile(logUser.getMobile());
                }
                throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301003);
            } else {
                String apiKey = callCenterOrganizationService.getApiKey(callTokenRefreshDTO.getCorpid(), moduleType);
                // 未获取token 或 已过期
                getToken(callCenterAccountUserInfoVO, apiKey);
                try {
                    CallCenterLoginVO loginVO = new CallCenterLoginVO();
                    BeanUtils.copyProperties(callTokenRefreshVO, loginVO);
                    initCallCenterAccountInfo(loginVO, callCenterAccountUserInfoVO);
                    BeanUtils.copyProperties(loginVO, callTokenRefreshVO);
                } catch (XbbException e) {
                    LOG.error(e.getMessage());
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018);
                }
            }
        }
        return new XbbResponse<>(callTokenRefreshVO);
    }

    /**
     * 获取手机验证码
     *
     * @param callMobileCodeSendDTO 获取手机验证码入参
     * @return
     * @throws XbbException 业务异常
     */
    @Override
    public XbbResponse<CallMobileCodeSendVO> mobileCodeSend(CallMobileCodeSendDTO callMobileCodeSendDTO) throws XbbException {
        CallMobileCodeSendVO callMobileCodeSendVO = new CallMobileCodeSendVO();
        Integer moduleType = callMobileCodeSendDTO.getModuleType();
        String mobile = callMobileCodeSendDTO.getMobile();
        if (notCallCenterModule(moduleType)) {
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301029);
        }
        if (isWrongMobilePhoneNum(mobile)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100027);
        }
        // 根据手机号查找话务中心平台账户是否已存在
        try {
            CallCenterAccountGetByMobileVO getByMobileVO = callCenterAccountService.getByMobile(mobile, moduleType);
            if (getByMobileVO != null) {
                if (Objects.equals(getByMobileVO.getCorpid(), callMobileCodeSendDTO.getCorpid())) {
                    // 是同一个公司内员工使用了该手机号
                    if (Objects.equals(getByMobileVO.getUserId(), callMobileCodeSendDTO.getUserId())) {
                        // 该手机号是同一个用户的
                        if (Objects.equals(getByMobileVO.getIsAgent(), 0)) {
                            // 当前用户未开通坐席
                            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301002);
                        }
                    } else {
                        // 该手机号是该公司用户当前话务中心的其他用户注册的
                        throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301066);
                    }
                }

            }
        } catch (XbbException e) {
            LOG.error(e.getMessage());
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301003);
        }

        String lastSend = paasRedisHelper.getValue(CallCenterConstant.REDIS_KEY_MOBILE_CODE_SEND, mobile);
        if (lastSend != null && UserConstant.REDIS_VALUE_MOBILE_CODE_SEND.equals(lastSend)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100009);
        }
        // 产生验证码,6位数字
        String mobileCode = StringUtil.getRandomPassword(1, 6);
        // 发送短信
        SmsSpacePojo smsCode = SMSSpaceService.sendCode(mobile, mobileCode);
        if (Objects.equals(smsCode.getSmsStatus(), "error")) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100010);
        }

        // 往redis添加数据
        paasRedisHelper.setValue(CallCenterConstant.REDIS_KEY_MOBILE_CODE, mobile, mobileCode, UserConstant.MOBILE_CODE_EFFECTIVE_TIME);
        paasRedisHelper.setValue(CallCenterConstant.REDIS_KEY_MOBILE_CODE_SEND, mobile, UserConstant.REDIS_VALUE_MOBILE_CODE_SEND,
                UserConstant.MOBILE_CODE_RESEND_DURATION);

        return new XbbResponse<>(callMobileCodeSendVO);
    }

    /**
     * 验证手机验证码
     *
     * @param callMobileCodeVerifyDTO 验证手机验证码入参
     * @return
     * @throws XbbException 业务异常
     */
    @Override
    public XbbResponse<CallMobileCodeVerifyVO> mobileCodeVerify(CallMobileCodeVerifyDTO callMobileCodeVerifyDTO) throws XbbException {
        CallMobileCodeVerifyVO callMobileCodeVerifyVO = new CallMobileCodeVerifyVO();
        Integer moduleType = callMobileCodeVerifyDTO.getModuleType();
        String mobile = callMobileCodeVerifyDTO.getMobile();
        if (notCallCenterModule(moduleType)) {
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301029);
        }
        if (isWrongMobilePhoneNum(mobile)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100027);
        }
        // 验证验证码合法性
        String trulyMobileCode = paasRedisHelper.getValue(CallCenterConstant.REDIS_KEY_MOBILE_CODE, mobile);
        if (StringUtil.isEmpty(trulyMobileCode) || !trulyMobileCode.equals(callMobileCodeVerifyDTO.getMobileCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006);
        }

        //验证一次后，将验证码失效
        paasRedisHelper.removeValue(CallCenterConstant.REDIS_KEY_MOBILE_CODE, mobile);

        // 完成用户话务中心的注册并返回token
        String apiKey = callCenterOrganizationService.getApiKey(callMobileCodeVerifyDTO.getCorpid(), moduleType);
        CallCenterAccountUserInfoDTO userInfoDTO = new CallCenterAccountUserInfoDTO();
        BeanUtils.copyProperties(callMobileCodeVerifyDTO, userInfoDTO);
        CallCenterAccountUserInfoVO callCenterAccountUserInfoVO = callCenterAccountService.getByXbbUserInfo(userInfoDTO);
        if (callCenterAccountUserInfoVO == null) {
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301003);
        }
        callCenterAccountUserInfoVO.setMobile(mobile);
        callCenterAccountUserInfoVO.setIsMobileVerified(1);

        CallCenterAccountEntity accountEntity = new CallCenterAccountEntity();
        BeanUtils.copyProperties(callCenterAccountUserInfoVO, accountEntity);
        try {
            if (!callCenterAccountService.updateThirdPlatformAccount(apiKey, accountEntity)) {
                // 更新第三方话务中心平台数据不成功，返回错误信息
                throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301010);
            }
        } catch (XbbException e) {
            LOG.error(e.getMessage());
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006);
        }

        // TODO 章华隽 2017-11-27 既然验证了用户的可靠手机号，是否同步到 tb_user 来补全缺失的用户手机号信息？钊琦表示当前不需要
        String token;
        try {
            token = getAccountToken(apiKey, accountEntity);
        } catch (XbbException e) {
            LOG.error(e.getMessage());
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018);
        }
        if (StringUtil.isEmpty(token)) {
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301004);
        }
        CallCenterLoginVO loginVO = new CallCenterLoginVO();
        BeanUtils.copyProperties(callMobileCodeVerifyVO, loginVO);
        try {
            initCallCenterAccountInfo(loginVO, callCenterAccountUserInfoVO);
            BeanUtils.copyProperties(loginVO, callMobileCodeVerifyVO);
        } catch (XbbException e) {
            LOG.error(e.getMessage());
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018);
        }
        return new XbbResponse<>(callMobileCodeVerifyVO);
    }

    /**
     * 移动端获取呼出号码（呼出线路）
     *
     * @param callMobileCallDTO 移动端获取呼出号码（呼出线路）
     * @return
     * @throws XbbException 业务异常
     */
    @Override
    public XbbResponse<CallMobileCallVO> mobileCall(CallMobileCallDTO callMobileCallDTO) throws XbbException {
        CallMobileCallVO callMobileCallVO = new CallMobileCallVO();
        Integer moduleType = callMobileCallDTO.getModuleType();
        String target = callMobileCallDTO.getTarget();
        if (notCallCenterModule(moduleType)) {
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301029);
        }
        if (isWrongMobilePhoneNum(target)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100027);
        }
        CallCenterAccountUserInfoDTO userInfoDTO = new CallCenterAccountUserInfoDTO();
        userInfoDTO.setCorpid(callMobileCallDTO.getCorpid());
        userInfoDTO.setUserId(callMobileCallDTO.getUserId());
        userInfoDTO.setModuleType(moduleType);
        String callPhoneNum = registerMobileTarget(userInfoDTO, target);
        if (StringUtil.isEmpty(callPhoneNum)) {
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301067);
        }
        callMobileCallVO.setCallPhoneNum(callPhoneNum);
        return new XbbResponse<>(callMobileCallVO);
    }

    /**
     * 获取移动端上的话务中心的筛选栏项目（度言）
     *
     * @param callAppFiltersDTO 获取移动端上的话务中心的筛选栏项目（度言）
     * @return
     * @throws XbbException 业务异常
     */
    @Override
    public XbbResponse<CallAppFiltersVO> workOrderFilterSet(CallAppFiltersDTO callAppFiltersDTO) throws XbbException {
        String userId = callAppFiltersDTO.getUserId();
        String corpid = callAppFiltersDTO.getCorpid();
        // 登录用户
        UserEntity logUser = userModel.getByKey(userId, corpid);
        if (logUser == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100004);
        }
        // 是否为公司的管理层
        boolean isBoss = userModel.isBoss(logUser);
        // 是否为呼叫中心的管理员
        boolean isCallCenterAdmin = false;
        // 是否为团队主管
        boolean isCallCenterSupervisor = false;
        // 话务中心角色
        // 当前公司没有开启呼叫中心
        CallCenterAccountUserInfoDTO userInfoDTO = new CallCenterAccountUserInfoDTO();
        BeanUtil.copyProperties(callAppFiltersDTO, userInfoDTO);
        CallCenterAccountUserInfoVO infoVO = callCenterAccountService.getByXbbUserInfo(userInfoDTO);
        if (infoVO == null) {
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301003);
        }
        if (Objects.equals(infoVO.getIsAdmin(), 1)) {
            isCallCenterAdmin = true;
        } else if (Objects.equals(infoVO.getIsSupervisor(), 1)) {
            isCallCenterSupervisor = true;
        }
        CallAppFiltersVO callAppFiltersVO = new CallAppFiltersVO();
        List<SelectPojo> selectPojoList = new ArrayList<>();
        if (isBoss || isCallCenterAdmin || isCallCenterSupervisor) {
            selectPojoList.add(initSearchUserFilter(isBoss, isCallCenterAdmin, isCallCenterSupervisor, logUser, infoVO));
        }
        selectPojoList.add(initSearchTypeFilter());
        selectPojoList.add(initSearchCallTimeFilter());
        callAppFiltersVO.setFilterList(selectPojoList);
        return new XbbResponse<>(callAppFiltersVO);
    }

    /**
     * 在度言平台注册企业信息
     *
     * @param corpid           企业id
     * @param moduleType       微应用平台
     * @param name             企业注册的全民
     * @param alias            企业简称
     * @param registerId       企业的统一信用代码
     * @param isAudioTranslate 语音翻译功能
     * @param platformLine
     * @param unitPrice
     * @return String 企业的org_id（失败则返回null）
     * @throws XbbException 业务错误
     * @author 章华隽
     * 创建时间：2017/11/2 下午3:59
     * 修改时间：
     * @version
     * @since 3.14
     */
    @Override
    public boolean registerOrganization(String corpid, Integer moduleType, String name, String alias, String registerId, Boolean isAudioTranslate, Integer platformLine, String unitPrice) throws XbbException {
        if (moduleType == CallCenterTypeEnum.CALL_CENTER_DU_YAN.getCode()) {
            DuYanOrganizationVO duYanOrganizationVO = duYanHttpService.registerOrganization(name, alias, registerId);
            if (duYanOrganizationVO == null || duYanOrganizationVO.getOrgId() == null) {
                return false;
            } else {
                String apiKey = duYanHttpService.getOrgApiKey(duYanOrganizationVO.getOrgId());
                if (StringUtil.isEmpty(apiKey)) {
                    return false;
                }
                CallCenterOrganizationEntity callCenterOrganizationEntity =
                        new CallCenterOrganizationEntity(corpid, duYanOrganizationVO.getOrgId().toString(),
                                moduleType, name, alias, registerId, apiKey, isAudioTranslate, platformLine, unitPrice);
                return callCenterOrganizationModel.insert(callCenterOrganizationEntity) > 0;
            }
        }
        return false;
    }

    /**
     * 设置员工权限时如果还未注册到话务中心平台，先进行注册
     *
     * @param apiKey     企业的话务中心校验码
     * @param moduleType 话务中心平台号
     * @param corpid     公司ID
     * @param userId     用户ID
     * @return CallCenterAccountUserInfoVO 注册成功的用户信息
     * @throws XbbException 销帮帮设定的异常
     * @author 章华隽
     * 创建时间：2017/11/08 下午5:00
     * 修改时间：
     * @version
     * @since 3.14
     */
    @Override
    public CallCenterAccountUserInfoVO registerAccount(String apiKey, Integer moduleType, String corpid, String userId) throws XbbException {
        CallCenterAccountUserInfoDTO userInfoDTO = new CallCenterAccountUserInfoDTO();
        userInfoDTO.setCorpid(corpid);
        userInfoDTO.setUserId(userId);
        userInfoDTO.setModuleType(moduleType);
        CallCenterAccountUserInfoVO userInfoVO = callCenterAccountService.getByXbbUserInfo(userInfoDTO);
        if (userInfoVO == null) {
            // 客户未向度言平台注册(区分销帮帮呼叫中心 youli.chen)
            try {
                if (!callCenterAccountService.saveAccount(userModel.getByKey(userId, corpid), moduleType, apiKey)) {
                    throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301068);
                }
            } catch (XbbException e) {
                LOG.error("话务中心注册员工时出错：", e);
                throw e;
            }
            userInfoVO = callCenterAccountService.getByXbbUserInfo(userInfoDTO);
            if (userInfoVO == null) {
                throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301030);
            }
        }
        return userInfoVO;
    }

    /**
     * 查找远程通话记录的详情
     *
     * @param apikey     公司在第三方话务平台的主键
     * @param moduleType 第三方话务平台，参考AppStoreTypeEnum
     * @param callUuid   通话录音的唯一标识
     * @return CallCenterCallLogEntity 封装的通话记录
     * @throws XbbException 销帮帮设定的异常
     * @author 章华隽
     * 创建时间：2017/11/24 下午3:02
     * 修改时间：
     * @version
     * @since 3.13.6
     */
    @Override
    public CallCenterCallLogEntity getOriginCallLogDetail(String apikey, Integer moduleType, String callUuid) throws XbbException {
        CallCenterCallLogEntity callLogEntity = new CallCenterCallLogEntity();
        if (moduleType == CallCenterTypeEnum.CALL_CENTER_DU_YAN.getCode()) {
            DuYanCallLogVO duYanCallLogVO = duYanHttpService.getCallLogDetail(apikey, callUuid);
            if (duYanCallLogVO == null) {
                return null;
            }
            packageDuYanCallLogEntity(callLogEntity, duYanCallLogVO);
        }
        return callLogEntity;
    }

    /**
     * 度言封装通话记录数据
     *
     * @param callLogEntity
     * @param duYanCallLogVO
     * @return
     */
    @Override
    public CallCenterCallLogEntity packageDuYanCallLogEntity(CallCenterCallLogEntity callLogEntity, DuYanCallLogVO duYanCallLogVO) {
        BeanUtils.copyProperties(callLogEntity, duYanCallLogVO);
        callLogEntity.setCorpid(StringConstant.PLATFORM_DUYAN);
        callLogEntity.setUserId(duYanCallLogVO.getAgent());
        callLogEntity.setRefId(0L);
        callLogEntity.setRefType(CallCenterTypeEnum.UNKNOWN.getCode());
        callLogEntity.setRefName("ant");
        callLogEntity.setModuleType(CallCenterTypeEnum.CALL_CENTER_DU_YAN.getCode());
        callLogEntity.setCallTime((int) (duYanCallLogVO.getCallTime() / 1000L));
        callLogEntity.setDuration(Integer.parseInt(duYanCallLogVO.getDuration().toString()));
        callLogEntity.setRingTime(Integer.parseInt(duYanCallLogVO.getRingTime().toString()));
        if (DuYanConstant.CALL_LOG_TYPE_OUTBOUND.equals(duYanCallLogVO.getType())) {
            // 呼出
            callLogEntity.setType(CallLogTypeEnum.OUTBOUND.getCode());
            callLogEntity.setAgentPhoneNum(duYanCallLogVO.getCaller());
            callLogEntity.setAnotherPhoneNum(duYanCallLogVO.getCallee());
        } else {
            // 呼出
            callLogEntity.setType(CallLogTypeEnum.INBOUND.getCode());
            callLogEntity.setAgentPhoneNum(duYanCallLogVO.getCaller());
            callLogEntity.setAnotherPhoneNum(duYanCallLogVO.getCallee());
        }
        callLogEntity.setResult(DuYanConstant.CALL_LOG_RESULT_SUCCESS.equals(duYanCallLogVO.getOutcome()) ?
                CallLogResultEnum.SUCCESS.getCode() : CallLogResultEnum.FAIL.getCode());
        return callLogEntity;
    }

    /**
     * 封装销帮帮呼叫中心通话记录数据
     *
     * @param callLogEntity
     * @param callCallLogSaveDTO
     * @return
     */
    @Override
    public CallCenterCallLogEntity packageXbbCallLogEntity(CallCenterCallLogEntity callLogEntity, CallCallLogSaveDTO callCallLogSaveDTO) {
        BeanUtils.copyProperties(callCallLogSaveDTO, callLogEntity);
        callLogEntity.setRefId(0L);
        callLogEntity.setRefType(CallCenterTypeEnum.UNKNOWN.getCode());
        callLogEntity.setRefName("ant");
        callLogEntity.setModuleType(CallCenterTypeEnum.CALL_CENTER_XBB.getCode());
        callLogEntity.setCallTime(callCallLogSaveDTO.getStartTime());
        callLogEntity.setRecordUrl(callCallLogSaveDTO.getRecordUrl());
        if (callCallLogSaveDTO.getAnswerTime() == null || callCallLogSaveDTO.getAnswerTime() == 0) {
            // 未接通的呼叫
            callLogEntity.setRingTime(callCallLogSaveDTO.getEndTime() - callCallLogSaveDTO.getStartTime());
            callLogEntity.setDuration(0);
            // 通话结果：失败
            callLogEntity.setResult(CallLogResultEnum.FAIL.getCode());
        } else {
            // 接通的呼叫
            callLogEntity.setRingTime(callCallLogSaveDTO.getAnswerTime() - callCallLogSaveDTO.getStartTime());
            callLogEntity.setDuration(callCallLogSaveDTO.getDuration());
            if (callCallLogSaveDTO.getEndTime() - callCallLogSaveDTO.getAnswerTime() < 0) {
                    LOG.info("corpid: {}通话记录异常数据记录{}",callLogEntity.getCorpid(), callCallLogSaveDTO);
            }
            // 通话结果：成功
            callLogEntity.setResult(CallLogResultEnum.SUCCESS.getCode());
        }
        return callLogEntity;
    }

    /**
     * 拨号后自动添加跟进记录
     *
     * @param autoCommunicateDTO 拨号后自动添加跟进记录入参
     * @author youli.chen
     * 创建时间：2018/12/11 下午4:51
     * @version v1.0
     * @since v1.0
     */
    @Override
    public AutoCommunicateVO autoCommunicate(AutoCommunicateDTO autoCommunicateDTO) throws XbbException {
        AutoCommunicateVO autoCommunicateVO = new AutoCommunicateVO();

        String corpid = autoCommunicateDTO.getCorpid();
        String userId = autoCommunicateDTO.getUserId();
        CallLogTypeEnum callLogTypeEnum = CallLogTypeEnum.getByCode(autoCommunicateDTO.getType());
        UserEntity logUser = userModel.getByKey(userId, corpid);
        if (logUser == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001.getCode(), MessageConstant.USER_NOT_EXIST);
        }
        String userName = logUser.getName();
        String userAvatar = logUser.getAvatar();
        Long refId = autoCommunicateDTO.getRefId();
        String target = autoCommunicateDTO.getAnotherPhoneNum();
        CustomerEntityExt customerEntityExt = null;
        ContactEntityExt contactEntityExt = null;
        ClueEntityExt clueEntityExt = null;
        XbbRefTypeEnum refTypeEnum = XbbRefTypeEnum.getByCode(autoCommunicateDTO.getRefType());
        // 客户ID
        Long customerId;
        switch (refTypeEnum) {
            case CUSTOMER_MANAGEMENT:
                customerEntityExt = customerModel.getByKey(refId, corpid);
                customerId = refId;
                break;
            case CONTACT:
                contactEntityExt = contactModel.getByKey(refId, corpid);
                if (contactEntityExt == null || contactEntityExt.getDel() == 1) {
                    return autoCommunicateVO;
                }
                customerId = contactEntityExt.getData().getLong(ContactEnum.CUSTOMER_NAME.getAttr());
                customerEntityExt = customerModel.getByKey(customerId, corpid);
                break;
            case CLUE:
                clueEntityExt = clueModel.getByKey(refId, corpid);
                if (clueEntityExt == null || clueEntityExt.getDel() == 1) {
                    return autoCommunicateVO;
                }
                customerId = refId;
                break;
            default:
                return autoCommunicateVO;
        }
        // 更新客户最后跟进时间(通话成功才更新),web端前面已经处理了，移动端这里再处理一下

        //"销帮帮呼叫中心"、"度言呼叫中心"、"钉钉"中的拨打时间影响最后跟进时间
        if(customerEntityExt != null){
            Boolean flag = paasFormService.getSingleRuleList(corpid, RuleSettingEnum.TELEPHONE_CONNECTION_DIAL_TIME.getConfig(), customerEntityExt.getFormId());
            if (flag) {
                // 因为无论通话是否成功，都有跟进记录生成，都更新 2019.12.12
                JSONObject jsonObject = new JSONObject();
                jsonObject.put(CustomerManagementEnum.LAST_CONNECT_TIME.getAttr(), DateTimeUtil.getInt());
                UpdateDataEntity updateData = ExplainUtil.getUpdateData(customerEntityExt.getId(), jsonObject, corpid);
                customerModel.updateBatch(Collections.singletonList(updateData), corpid);
                //评分更新(打电话，更新最后跟进时间)
                scoreCalculateService.asyncUpdateSingleDataScore(XbbRefTypeEnum.CUSTOMER_MANAGEMENT,corpid,null,customerEntityExt);
            }
        }
        if(clueEntityExt != null){
            Boolean flag = proFormHelp.getClueSingleRuleList(corpid, ClueRuleSettingEnum.TELEPHONE_CONNECTION_DIAL_TIME.getConfig(), clueEntityExt.getFormId());
            if (flag) {
                // 因为无论通话是否成功，都有跟进记录生成，都更新 2019.12.12
                JSONObject data = clueEntityExt.getData();
                data.put(ClueEnum.LAST_CONNECT_TIME.getAttr(), DateTimeUtil.getInt());
                FormDataUtil.removeSystemData(data);
                clueEntityExt.setData(data);
                clueModel.update(clueEntityExt);
                //更新评分(打电话，更新最后跟进时间)
                scoreCalculateService.asyncUpdateSingleDataScore(XbbRefTypeEnum.CLUE,corpid,null,clueEntityExt);
            }
        }

        if (customerEntityExt == null && clueEntityExt == null) {
            return autoCommunicateVO;
        }
        XbbRefTypeEnum moduleTypeEnum = XbbRefTypeEnum.getByCode(autoCommunicateDTO.getModuleType());
        // 平台名称
        String platform = moduleTypeEnum.getName();
        if (moduleTypeEnum == XbbRefTypeEnum.CALL_CENTER_DU_YAN || moduleTypeEnum == XbbRefTypeEnum.CALL_CENTER_XBB) {
            // 所有话务中心的平台统一显示
            platform = XbbRefTypeEnum.CALL_CENTER.getName();
        }
        // 加密手机号
        target = StringUtil.secretPhoneNum(target);
        Long contactId = contactEntityExt == null ? 0L : contactEntityExt.getId();
        // 联系人姓名
        String contactName = "";
        if (contactEntityExt != null){
            contactName = FastJsonHelper.getStringOrDefaultFromFormData(contactEntityExt.getData(), ContactEnum.NAME.getAttr(), "");
        }
        // 客户姓名
        String customerName = "";
        if(customerEntityExt != null){
            customerName = FastJsonHelper.getStringOrDefaultFromFormData(customerEntityExt.getData(), CustomerManagementEnum.NAME.getAttr(), "");
        }
        Long clueId = clueEntityExt == null ? 0L : clueEntityExt.getId();
        // 线索名称
        String clueName = "";
        if(contactEntityExt == null && customerEntityExt == null && clueEntityExt != null){
            clueName = FastJsonHelper.getStringOrDefaultFromFormData(clueEntityExt.getData(), ClueEnum.COMPANY_NAME.getAttr(), "");
        }

        String callDuration = "";
        String dynamicCallDuration = "";
        Integer result = autoCommunicateDTO.getResult();
        Integer duration = autoCommunicateDTO.getDuration();
        if(result != null && duration != null){
            if(Objects.equals(result,CallLogResultEnum.FAIL.getCode())){
                callDuration = String.format(I18nMessageUtil.getMessage(CallCenterMemoConstant.COMMUNICATE_NOT_CONNECTED));
                dynamicCallDuration = callDuration;
            } else {
                String time = DateUtil.secondToTimeTip(duration);
                callDuration = String.format(I18nMessageUtil.getMessage(CallCenterMemoConstant.COMMUNICATE_CONNECTION_TIME), time);
                dynamicCallDuration = String.format(I18nMessageUtil.getMessage(CrmLogMemoConstant.COMMUNICATE_CONNECTION_TIME), time);
            }
        }

        String memo;
        String dynamicMemo;
        switch (callLogTypeEnum) {
            case INBOUND:
                // 呼入
                if (Objects.equals(refTypeEnum, XbbRefTypeEnum.CUSTOMER_MANAGEMENT)) {
                    memo = String.format(I18nMessageUtil.getMessage(CallCenterMemoConstant.COMMUNICATE_CUSTOMER_INBOUND), platform, target);
                    dynamicMemo = String.format(I18nMessageUtil.getMessage(CrmLogMemoConstant.COMMUNICATE_CUSTOMER_INBOUND), platform, target);
                } else if (Objects.equals(refTypeEnum, XbbRefTypeEnum.CONTACT)) {
                    memo = String.format(I18nMessageUtil.getMessage(CallCenterMemoConstant.COMMUNICATE_CONTACT_INBOUND), platform, contactName, target);
                    dynamicMemo = String.format(I18nMessageUtil.getMessage(CrmLogMemoConstant.COMMUNICATE_CONTACT_INBOUND), platform, contactName, target);
                } else {
                    memo = String.format(I18nMessageUtil.getMessage(CallCenterMemoConstant.COMMUNICATE_CLUE_INBOUND), platform, clueName, target);
                    dynamicMemo = String.format(I18nMessageUtil.getMessage(CallCenterMemoConstant.COMMUNICATE_CLUE_INBOUND), platform, clueName, target);
                }
                break;
            case OUTBOUND:
                // 呼出
                if (Objects.equals(refTypeEnum, XbbRefTypeEnum.CUSTOMER_MANAGEMENT)) {
                    memo = String.format(I18nMessageUtil.getMessage(CallCenterMemoConstant.COMMUNICATE_CUSTOMER_OUTBOUND), platform, target);
                    dynamicMemo = String.format(I18nMessageUtil.getMessage(CrmLogMemoConstant.COMMUNICATE_CUSTOMER_OUTBOUND), platform, target);
                } else if (Objects.equals(refTypeEnum, XbbRefTypeEnum.CONTACT)) {
                    memo = String.format(I18nMessageUtil.getMessage(CallCenterMemoConstant.COMMUNICATE_CONTACT_OUTBOUND), platform, contactName, target);
                    dynamicMemo = String.format(I18nMessageUtil.getMessage(CrmLogMemoConstant.COMMUNICATE_CONTACT_OUTBOUND), platform, contactName, target);
                } else {
                    memo = String.format(I18nMessageUtil.getMessage(CallCenterMemoConstant.COMMUNICATE_CLUE_OUTBOUND), platform, clueName, target);
                    dynamicMemo = String.format(I18nMessageUtil.getMessage(CallCenterMemoConstant.COMMUNICATE_CLUE_OUTBOUND), platform, clueName, target);
                }
                break;
            default:
                return autoCommunicateVO;
        }

        if(Objects.equals(autoCommunicateDTO.getPlatform(), PlatFormEnum.WEB.getValue())){
            memo = String.format(CallCenterMemoConstant.COMMUNICATE_PING, memo, callDuration);
            dynamicMemo = String.format(CallCenterMemoConstant.COMMUNICATE_PING, dynamicMemo, dynamicCallDuration);
        }

        CallCommunicateDTO callCommunicateDTO = packCallCommunicate(corpid, userId, userName, userAvatar,
                customerId, customerName, autoCommunicateDTO.getStartTime(), memo, contactId, contactName,
                autoCommunicateDTO.getRefType(), clueId, clueName);
        callCommunicateDTO.setDynamicMemo(dynamicMemo);
        customerCommunicateService.autoAfterCallCommunicate(callCommunicateDTO);
        return autoCommunicateVO;
    }

    /**
     * 根据对象的通话号码查找对象（客户或联系人或线索）
     *
     * @param corpid    公司id
     * @param refMobile 用于查询的通话号码
     * @return Object 对象（客户或联系人）
     * @author 章华隽
     * 创建时间：2017/11/1 上午10:19
     * 修改时间：
     * @version
     * @since 3.14
     */
    @Override
    public CallCenterFindRefDTO findRefByPhoneNum(String corpid, String refMobile) throws XbbException {
        CallCenterFindRefDTO callCenterFindRefDTO = new CallCenterFindRefDTO();
        CustomerEntityExt customerEntityExt = customerModel.getByPhone(corpid, refMobile);
        if (customerEntityExt == null) {
            ContactEntityExt contactEntityExt = contactModel.getByPhone(corpid, refMobile);
            if (contactEntityExt == null) {
                ClueEntityExt clueEntityExt = clueModel.getByPhone(corpid, refMobile);
                if (clueEntityExt == null) {
                    callCenterFindRefDTO.setRefId(0L);
                    callCenterFindRefDTO.setRefName(String.format(I18nMessageUtil.getMessage(I18nStringConstant.STRANGE_NUMBER) + "【%s】", refMobile));
                    callCenterFindRefDTO.setRefType(CallCenterTypeEnum.UNKNOWN.getCode());
                } else {
                    callCenterFindRefDTO.setRefType(XbbRefTypeEnum.CLUE.getCode());
                    Long clueId = clueEntityExt.getId();
                    if (clueId != null) {
                        callCenterFindRefDTO.setRefId(clueId);
                    }
                    if (clueEntityExt.getData() != null) {
                        callCenterFindRefDTO.setRefName(clueEntityExt.getData().getString(ClueEnum.COMPANY_NAME.getAttr()));
                    }
                }
            } else {
                callCenterFindRefDTO.setRefType(XbbRefTypeEnum.CONTACT.getCode());
                Long contactId = contactEntityExt.getId();
                if (contactId != null) {
                    callCenterFindRefDTO.setRefId(contactId);
                }
                if (contactEntityExt.getData() != null) {
                    Long contactCustomerId = contactEntityExt.getData().getLong(ContactEnum.CUSTOMER_NAME.getAttr());
                    if (contactCustomerId != null) {
                        callCenterFindRefDTO.setCustomerId(contactCustomerId.intValue());
                    }
                    callCenterFindRefDTO.setRefName(contactEntityExt.getData().getString(ContactEnum.NAME.getAttr()));
                    callCenterFindRefDTO.setCustomerName(contactEntityExt.getData().getString(ContactEnum.CUSTOMER_NAME.getAttr()));
                }
            }
        } else {
            callCenterFindRefDTO.setRefType(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode());
            Long customerId = customerEntityExt.getId();
            if (customerId != null) {
                callCenterFindRefDTO.setRefId(customerId);
            }
            if (customerEntityExt.getData() != null) {
                callCenterFindRefDTO.setRefName(customerEntityExt.getData().getString(ContactEnum.NAME.getAttr()));
            }
        }
        return callCenterFindRefDTO;
    }

    /**
     * 同步组织架构到度言（销帮帮）
     *
     * @param callSyncDepartmentDTO 同步组织架构到度言（销帮帮）入参
     * @return CallSyncDepartmentVO  同步组织架构到度言（销帮帮）回参
     * @throws XbbException 业务异常
     */
    @Override
    public XbbResponse<CallSyncDepartmentVO> syncDepartment(CallSyncDepartmentDTO callSyncDepartmentDTO) throws XbbException {
        CallSyncDepartmentVO callSyncDepartmentVO = new CallSyncDepartmentVO();
        String corpid = callSyncDepartmentDTO.getCorpid();
        Integer moduleType = callSyncDepartmentDTO.getModuleType();
        if (moduleType.equals(CallCenterTypeEnum.CALL_CENTER_DU_YAN.getCode())) {
            syncCallCenterDepartment(corpid, moduleType, callSyncDepartmentDTO.getDepId(), null);
        }
        return new XbbResponse<>(callSyncDepartmentVO);
    }

    /**
     * 客户防骚扰缓存比对
     *
     * @param callCustomerDisturbDTO 客户防骚扰缓存比对入参
     * @return CallCustomerDisturbVO  客户防骚扰缓存比对回参
     * @throws XbbException 业务异常
     */
    @Override
    public XbbResponse<CallCustomerDisturbVO> customerDisturb(CallCustomerDisturbDTO callCustomerDisturbDTO) throws XbbException {
        CallCustomerDisturbVO callCustomerDisturbVO = new CallCustomerDisturbVO();
        String corpid = callCustomerDisturbDTO.getCorpid();
        CustomerEntityExt cusEntityExt = customerModel.getByPhone(corpid, callCustomerDisturbDTO.getPhone());
        if (cusEntityExt == null) {
            // 陌生客户不考虑骚扰问题
            return new XbbResponse<>(callCustomerDisturbVO);
        }
        String customerId = String.valueOf(cusEntityExt.getId());
        XbbResponse<CallCenterConfigVO> configResponse = callCenterConfigService.getByCorpId(corpid, null);
        CallCenterConfigVO callCenterConfigVO = configResponse.getResult();
        if (callCenterConfigVO == null) {
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301051);
        }
        if (Objects.equals(callCenterConfigVO.getIsAntiDisturb(), 1)) {
            int countDayNum = 0;
            int countWeekNum = 0;
            int countMonthNum = 0;
            if (paasRedisHelper.getValue(CallCenterConstant.CUSTOMER_DISTURB_DAY, corpid + "_" + customerId) != null) {
                countDayNum = Integer.parseInt(paasRedisHelper.getValue(CallCenterConstant.CUSTOMER_DISTURB_DAY,
                        corpid + "_" + customerId));
            }
            if (paasRedisHelper.getValue(CallCenterConstant.CUSTOMER_DISTURB_WEEK, corpid + "_" + customerId) != null) {
                countWeekNum = Integer.parseInt(paasRedisHelper.getValue(CallCenterConstant.CUSTOMER_DISTURB_WEEK,
                        corpid + "_" + customerId));
            }
            if (paasRedisHelper.getValue(CallCenterConstant.CUSTOMER_DISTURB_MONTH, corpid + "_" + customerId) != null) {
                countMonthNum = Integer.parseInt(paasRedisHelper.getValue(CallCenterConstant.CUSTOMER_DISTURB_MONTH,
                        corpid + "_" + customerId));
            }
            if (countDayNum >= callCenterConfigVO.getCallNumPerDay() && !Objects.equals(callCenterConfigVO.getCallNumPerDay(), 0)) {
                throw new XbbException(XbbCallErrorCodeEnum.API_ERROR_400001);
            } else if (countWeekNum >= callCenterConfigVO.getCallNumPerWeek() && !Objects.equals(callCenterConfigVO.getCallNumPerWeek(), 0)) {
                throw new XbbException(XbbCallErrorCodeEnum.API_ERROR_400002);
            } else if (countMonthNum >= callCenterConfigVO.getCallNumPerMonth() && !Objects.equals(callCenterConfigVO.getCallNumPerMonth(), 0)) {
                throw new XbbException(XbbCallErrorCodeEnum.API_ERROR_400003);
            }
        }
        return new XbbResponse<>(callCustomerDisturbVO);
    }

    /**
     * 如果公司未同步组织架构，则同步公司的组织架构去第三方话务中心平台维护
     *
     * @param corpid          公司id
     * @param moduleType      第三方话务平台，参考AppStoreTypeEnum
     * @param depId           部门id
     * @param phoneVisibility 号码是否对团队成员隐藏:PUBLIC:公开,PRIVATE:隐藏,MEMBER_PRIVATE:对团队管理员公开,普通坐席隐藏
     * @return List<CallCenterTeamEntity> 组装的本地维护的企业部门，缺少orgId
     * @throws XbbException 业务异常
     * @author youli.chen
     * 创建时间：2017/11/1 上午10:19
     * @version v1.0
     * @since v1.0
     */
    @Override
    public void syncCallCenterDepartment(String corpid, Integer moduleType, Long depId, String phoneVisibility) throws XbbException {
        CallCenterTeamEntity teamEntity = callCenterTeamService.getByXbbDepInfo(corpid, depId, moduleType);
        if (teamEntity != null) {
            return;
        }
        boolean isPhoneVisibilityEmpty = StringUtil.isEmpty(phoneVisibility);
        boolean isPhoneVisibilityLegal = DuYanConstant.PHONE_VISIBILITY_PUBLIC.equals(phoneVisibility) ||
                DuYanConstant.PHONE_VISIBILITY_MEMBER_PRIVATE.equals(phoneVisibility) ||
                DuYanConstant.PHONE_VISIBILITY_PRIVATE.equals(phoneVisibility);
        if (isPhoneVisibilityEmpty || !isPhoneVisibilityLegal) {
            phoneVisibility = DuYanConstant.PHONE_VISIBILITY_PUBLIC;
        }
        CallCenterOrgGetByCorpIdVO getByCorpIdVO = callCenterOrganizationService.getByCorpId(corpid, moduleType);
        if (getByCorpIdVO == null) {
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301001);
        }
        String apiKey = null;
        if (moduleType.equals(CallCenterTypeEnum.CALL_CENTER_DU_YAN.getCode())) {
            apiKey = getByCorpIdVO.getApikey();
            if (StringUtil.isEmpty(apiKey)) {
                throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301001);
            }
        }
        departmentService.setIfJedis(true);
        List<DepartmentEntity> departmentEntityList = departmentService.getAllDepList(corpid);
        departmentService.setIfJedis(false);
        if (departmentEntityList.size() == 0) {
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301069);
        }
        List<DepartmentEntity> treeDepartmentList = new ArrayList<>();
        boolean isAllDepCorrect = false;
        try {
            isAllDepCorrect = catchDepartmentTreeSizeException(StringConstant.VERTICAL_LINE + 1 + StringConstant.VERTICAL_LINE,
                    departmentEntityList, moduleType);
            treeDepartmentList = departmentEntityList;
        } catch (XbbException e) {
            LOG.error("公司（%s）的部门层级超过话务中心（%s）的限制要求，尝试个别部门同步", corpid, moduleType);
        }
        // 该公司全部门的层级超过上限
        if (!isAllDepCorrect) {
            // 本部门以及所有子部门队列
            String rootDepId = StringConstant.VERTICAL_LINE + depId.toString() + StringConstant.VERTICAL_LINE;
            for (DepartmentEntity departmentEntity : departmentEntityList) {
                if (departmentEntity.getDepIdRouter().contains(rootDepId)) {
                    treeDepartmentList.add(departmentEntity);
                }
            }
            if (treeDepartmentList.size() == 0) {
                throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301070);
            }
            catchDepartmentTreeSizeException(rootDepId, treeDepartmentList, moduleType);
        }

        if (moduleType.equals(CallCenterTypeEnum.CALL_CENTER_DU_YAN.getCode())) {
            try {
                syncCallCenterDepartment(corpid, getByCorpIdVO.getOrgId(), apiKey, moduleType, treeDepartmentList, phoneVisibility);
            } catch (XbbException e) {
                LOG.error("话务中心同步组织架构时出错：", e);
                throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301071);
            }
        } else if (moduleType.equals(CallCenterTypeEnum.CALL_CENTER_XBB.getCode())) {
            try {
                syncDepartmentByXbb(corpid, moduleType, treeDepartmentList);
            } catch (XbbException e) {
                LOG.error("话务中心同步组织架构时出错：", e);
                throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301071);
            }
        }
    }

    /**
     * 校验公司启用的组织架构层级并返回公司的组织架构
     *
     * @param moduleType           第三方话务平台，参考AppStoreTypeEnum
     * @param rootDepIdStr         需要校验的部门队列的根部门的部门id字符串（包含前后"|"）
     * @param departmentEntityList 公司需要同步的组织架构，进行同步
     * @return List<DepartmentEntity> 公司的组织架构
     * @author youli.chen
     * 创建时间：2017/11/1 上午10:19
     * @version v1.0
     * @since v1.0
     */
    @Override
    public boolean checkDepartmentRouter(Integer moduleType, String rootDepIdStr, List<DepartmentEntity> departmentEntityList) {
        if (Objects.equals(moduleType, CallCenterTypeEnum.CALL_CENTER_DU_YAN.getCode()) ||
                Objects.equals(moduleType, CallCenterTypeEnum.CALL_CENTER_XBB.getCode())) {
            if (departmentEntityList.size() > 0) {
                for (DepartmentEntity it : departmentEntityList) {
                    String depIdRouter = it.getDepIdRouter();
                    if (StringUtil.isEmpty(depIdRouter) || !depIdRouter.contains(StringConstant.VERTICAL_LINE)) {
                        continue;
                    }
                    int index = depIdRouter.indexOf(rootDepIdStr);
                    if (index > 0) {
                        depIdRouter = depIdRouter.substring(index, depIdRouter.length());
                    }
                    // "|"需要转译，在前面添加"\\"进行转译
                    if (StringUtil.countCharsNum(depIdRouter, "\\" + StringConstant.VERTICAL_LINE) > DuYanConstant.DEPARTMENT_ROUTE_LIMIT) {
                        // 度言方面只允许公司存在至多9级的组织架构
                        return false;
                    }
                }
            }
            return true;
        }
        return false;
    }

    /**
     * 同步公司的组织架构去第三方话务中心平台维护
     *
     * @param corpid          公司id
     * @param orgId           公司在第三方话务中心的公司id
     * @param apiKey          公司在第三方话务平台的主键
     * @param moduleType      第三方话务平台，参考AppStoreTypeEnum
     * @param depList         公司的所有部门
     * @param phoneVisibility 号码是否对团队成员隐藏:PUBLIC:公开,PRIVATE:隐藏,MEMBER_PRIVATE:对团队管理员公开,普通坐席隐藏
     * @return List<CallCenterTeamEntity> 组装的本地维护的企业部门，缺少orgId
     * @throws XbbException 业务异常
     * @author youli.chen
     * 创建时间：2017/11/1 上午10:19
     * @version v1.0
     * @since v1.0
     */
    @Override
    public void syncCallCenterDepartment(String corpid, String orgId, String apiKey, Integer moduleType,
                                         List<DepartmentEntity> depList, String phoneVisibility) throws XbbException {
        List<CallCenterTeamEntity> syncedCallCenterTeamList = new ArrayList<>();
        if (Objects.equals(moduleType, CallCenterTypeEnum.CALL_CENTER_DU_YAN.getCode())) {
            // 先将所有部门注册到度言
            for (DepartmentEntity it : depList) {
                if (callCenterTeamService.getByXbbDepInfo(corpid, it.getId(), moduleType) != null) {
                    continue;
                }
                DuYanTeamVO duYanTeamVO = duYanHttpService.registerTeam(apiKey, new DuYanTeamVO(it.getName(), phoneVisibility));
                LOG.info("度言团队注册之后的信息：" + duYanTeamVO);

                CallCenterTeamEntity callCenterTeamEntity = new CallCenterTeamEntity();
                callCenterTeamEntity.setCorpid(corpid);
                callCenterTeamEntity.setOrgId(orgId);
                callCenterTeamEntity.setDepId(it.getId());
                callCenterTeamEntity.setParentDepId(it.getParentId());
                callCenterTeamEntity.setDepIdRouter(it.getDepIdRouter());
                callCenterTeamEntity.setTeamId(duYanTeamVO.getTeamId().toString());
                callCenterTeamEntity.setModuleType(moduleType);
                callCenterTeamEntity.setName(duYanTeamVO.getName());
                callCenterTeamEntity.setPhoneVisibility(duYanTeamVO.getPhoneVisibility());
                syncedCallCenterTeamList.add(callCenterTeamEntity);
            }
            // 同步企业的组织架构，持久化到本地数据库
            if (syncedCallCenterTeamList.size() > 0) {
                LOG.info("组织架构，持久化到话务中心本地数据库：" + syncedCallCenterTeamList);
                callCenterTeamModel.batchInsert(syncedCallCenterTeamList);
            }
            // 本次同步的部门
            Map<Long, CallCenterTeamEntity> syncedTeamMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (CallCenterTeamEntity it : syncedCallCenterTeamList) {
                syncedTeamMap.put(it.getDepId(), it);
            }
            // 再将所有有父部门的进行更新
            for (DepartmentEntity it : depList) {
                // 该部门的父部门在本次的同步部门队列中
                CallCenterTeamEntity parentSyncedTeam;
                CallCenterTeamEntity syncedTeam = syncedTeamMap.get(it.getId());
                // 该部门的父部门在本次同步中进行了同步
                if (syncedTeamMap.containsKey(it.getParentId())) {
                    // 判断该部门是否也是本次同步
                    if (syncedTeam == null) {
                        // 该部门已经提前同步到度言，尝试从数据库获取
                        syncedTeam = callCenterTeamService.getByXbbDepInfo(corpid, it.getId(), moduleType);
                        if (syncedTeam == null) {
                            // 该部门已经被删除
                            continue;
                        }
                    }
                    // 有父级部门的先查找父级部门注册在度言方面的teamId
                    parentSyncedTeam = syncedTeamMap.get(it.getParentId());
                } else {
                    if (syncedTeam == null) {
                        continue;
                    }
                    // 该部门的父部门不在本次的同步队列中
                    parentSyncedTeam = callCenterTeamService.getByXbbDepInfo(corpid, it.getParentId(), moduleType);
                }
                if (parentSyncedTeam == null) {
                    // 该部门的父部门本次没有同步
                    continue;
                }
                if (!Objects.equals(syncedTeam.getParentId(), parentSyncedTeam.getTeamId())) {
                    // 当前部门的话务中心父部门平台与此次同步的父部门不同
                    syncedTeam.setParentDepId(it.getParentId());
                    syncedTeam.setDepIdRouter(it.getDepIdRouter());
                    syncedTeam.setParentId(parentSyncedTeam.getTeamId());
                    if (syncedTeam.getId() != null) {
                        callCenterTeamModel.update(syncedTeam);
                    }
                    try {
                        duYanHttpService.updateTeam(apiKey, new DuYanTeamVO(syncedTeam));
                    } catch (XbbException ignore) {
                        // 子部门更新失败，则忽略，不影响剩余部门同步
                    }
                }
            }
        }
    }

    /**
     * 切换员工的呼叫中心部门
     *
     * @param corpid     公司id
     * @param userInfoVO 员工的本地持久化呼叫中心账户
     * @param depId      部门id
     * @return 保存成功与否
     * @throws XbbException 业务异常
     * @author youli.chen
     * 创建时间：2017/11/1 上午10:19
     * @version v1.0
     * @since v1.0
     */
    @Override
    public boolean changeAccountDep(String corpid, CallCenterAccountUserInfoVO userInfoVO, Long depId) throws XbbException {
        CallCenterTeamEntity callCenterTeamEntity = callCenterTeamService.getByXbbDepInfo(corpid, depId, userInfoVO.getModuleType());
        if (callCenterTeamEntity == null) {
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301060);
        }
        if (userInfoVO.getModuleType() == CallCenterTypeEnum.CALL_CENTER_DU_YAN.getCode()) {
            if (Objects.equals(userInfoVO.getIsAgent(), 0)) {
                // TODO 度言暂时保留这个设定（确保有accountId参数）
                throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301072);
            }
            String apiKey = callCenterOrganizationService.getApiKey(corpid, userInfoVO.getModuleType());
            DuYanAccountVO duYanAccountVO = duYanHttpService.updateAccountTeam(apiKey, userInfoVO.getAccountId(),
                    Long.parseLong(callCenterTeamEntity.getTeamId()), Objects.equals(userInfoVO.getIsSupervisor(), 1));
            userInfoVO.setDepId(depId);
            userInfoVO.setTeamId(callCenterTeamEntity.getTeamId());
            userInfoVO.setIsAgent(duYanAccountVO.getIsAgent() ? 1 : 0);
            userInfoVO.setIsSupervisor(duYanAccountVO.getIsSupervisor() ? 1 : 0);

            CallCenterAccountEntity callCenterAccountEntity = new CallCenterAccountEntity();
            BeanUtils.copyProperties(userInfoVO, callCenterAccountEntity);

            return callCenterAccountModel.update(callCenterAccountEntity) > 0;
        } else if (userInfoVO.getModuleType() == CallCenterTypeEnum.CALL_CENTER_XBB.getCode()) {
            userInfoVO.setDepId(depId);
            userInfoVO.setTeamId(callCenterTeamEntity.getTeamId());

            CallCenterAccountEntity callCenterAccountEntity = new CallCenterAccountEntity();
            BeanUtils.copyProperties(userInfoVO, callCenterAccountEntity);

            return callCenterAccountModel.update(callCenterAccountEntity) > 0;
        }
        return false;
    }

    /**
     * 清除员工的话务中心角色
     *
     * @param corpId 公司id
     * @param userId 用户id
     * @author 陈有利
     * 创建时间：2017/12/15 上午9:51
     * 修改时间：
     * @version
     */
    @Override
    public void removeCallCenterPosition(String corpId, String userId) throws XbbException{
        List<Integer> moduleTypeList = Arrays.asList(CallCenterTypeEnum.CALL_CENTER_DU_YAN.getCode(),
                CallCenterTypeEnum.CALL_CENTER_XBB.getCode());
        for (Integer moduleType : moduleTypeList) {
            // 循环删除所有话务中心的角色
            CallCenterOrgGetByCorpIdVO orgVo = callCenterOrganizationService.getByCorpId(corpId, moduleType);
            if (orgVo == null) {
                continue;
            }
            String apiKey = orgVo.getApikey();
            CallCenterAccountUserInfoDTO callCenterAccountUserInfoDTO = new CallCenterAccountUserInfoDTO();
            callCenterAccountUserInfoDTO.setCorpid(corpId);
            callCenterAccountUserInfoDTO.setUserId(userId);
            callCenterAccountUserInfoDTO.setModuleType(moduleType);
            CallCenterAccountUserInfoVO infoVO = callCenterAccountService.getByXbbUserInfo(callCenterAccountUserInfoDTO);
            if (infoVO == null) {
                continue;
            }
            try {
                CallCenterAccountEntity callCenterAccountEntity = new CallCenterAccountEntity();
                BeanUtil.copyProperties(infoVO, callCenterAccountEntity);
                // 取消管理员
                LOG.info("removeCallCenterPosition----开始取消管理员");
                if (infoVO.getIsAdmin() == 1) {
                    callCenterAccountService.setAdmin(apiKey, callCenterAccountEntity, false);
                }
                // 取消团队主管
                LOG.info("removeCallCenterPosition----开始取消团队主管");
                if (callCenterAccountEntity.getIsSupervisor() == 1) {
                    callCenterAccountService.setSupervisor(apiKey, callCenterAccountEntity, false);
                }
                CallCenterTeamEntity callCenterTeamEntity = callCenterTeamService.getByXbbDepInfo(corpId, callCenterAccountEntity.getDepId(), moduleType);
                if (callCenterTeamEntity == null) {
                    // 数据库数据异常
                    continue;
                }
                // 取消坐席
                LOG.info("removeCallCenterPosition----开始取消坐席");
                if (callCenterAccountEntity.getIsAgent() == 1) {
                    if (callCenterAccountService.setAgent(apiKey, callCenterAccountEntity, callCenterTeamEntity, false)) {
                        Integer agentNum = callCenterAccountService.countAgentNum(corpId, moduleType);
                        agentNum--;
                        agentNum = agentNum < 0 ? 0 : agentNum;
                        LOG.info("removeCallCenterPosition----更新Redis中记录话务中心企业已经开启的坐席数");
                        paasRedisHelper.setValue(CallCenterConstant.REDIS_KEY_AGENT_NUM, corpId + StringConstant.COLON + moduleType,
                                agentNum.toString(), RedisConstant.COMMON_DURATION);
                    }
                }
                // 员工离职之后应该直接从话务中心的员工中删除
                callCenterAccountModel.deleteByKey(infoVO.getId(), corpId);
            } catch (XbbException e) {
                LOG.error(String.format("员工离职清空话务中心角色失败，corpid（%s），userId（%s），\n错误信息：%s", corpId, userId, e), "ERROR");
            }
        }
    }

    @Override
    public AddCommunicateVO addCommunicate(AddCommunicateDTO addCommunicateDTO) throws XbbException {
        AddCommunicateVO addCommunicateVO = new AddCommunicateVO();
        String result = "未从客户、联系人、线索找到匹配信息";
        addCommunicateVO.setResult(result);
        String corpid = addCommunicateDTO.getCorpid();
        String userId = addCommunicateDTO.getUserId();
        UserEntity logUser = userModel.getByKey(userId, corpid);
        if (logUser == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001.getCode(), MessageConstant.USER_NOT_EXIST);
        }
        String userName = logUser.getName();
        String userAvatar = logUser.getAvatar();
        Long refId = addCommunicateDTO.getRefId();
        String target = addCommunicateDTO.getAnotherPhoneNum();
        CustomerEntityExt customerEntityExt = null;
        ContactEntityExt contactEntityExt = null;
        ClueEntityExt clueEntityExt = null;
        XbbRefTypeEnum refTypeEnum = XbbRefTypeEnum.getByCode(addCommunicateDTO.getRefType());
        // 客户ID
        Long customerId;
        switch (refTypeEnum) {
            case CUSTOMER_MANAGEMENT:
                customerEntityExt = customerModel.getByKey(refId, corpid);
                if (customerEntityExt == null || customerEntityExt.getDel() == 1) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001,addCommunicateVO.getResult());
                }
                customerId = refId;
                result = "新增客户跟进记录成功";
                break;
            case CONTACT:
                contactEntityExt = contactModel.getByKey(refId, corpid);
                if (contactEntityExt == null || contactEntityExt.getDel() == 1) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001,addCommunicateVO.getResult());
                }
                customerId = contactEntityExt.getData().getLong(ContactEnum.CUSTOMER_NAME.getAttr());
                customerEntityExt = customerModel.getByKey(customerId, corpid);
                result = "新增联系人跟进记录成功";
                break;
            case CLUE:
                clueEntityExt = clueModel.getByKey(refId, corpid);
                if (clueEntityExt == null || clueEntityExt.getDel() == 1) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001,addCommunicateVO.getResult());
                }
                customerId = refId;
                result = "新增线索跟进记录成功";
                break;
            default:
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001,addCommunicateVO.getResult());
        }
        Long contactId = contactEntityExt == null ? 0L : contactEntityExt.getId();
        // 联系人姓名
        String contactName = "";
        if (contactEntityExt != null){
            contactName = FastJsonHelper.getStringOrDefaultFromFormData(contactEntityExt.getData(), ContactEnum.NAME.getAttr(), "");
        }
        // 客户姓名
        String customerName = "";
        if(customerEntityExt != null){
            customerName = FastJsonHelper.getStringOrDefaultFromFormData(customerEntityExt.getData(), CustomerManagementEnum.NAME.getAttr(), "");
        }
        Long clueId = clueEntityExt == null ? 0L : clueEntityExt.getId();
        // 线索名称
        String clueName = "";
        if(contactEntityExt == null && customerEntityExt == null && clueEntityExt != null){
            clueName = FastJsonHelper.getStringOrDefaultFromFormData(clueEntityExt.getData(), ClueEnum.COMPANY_NAME.getAttr(), "");
        }
        String memo=addCommunicateDTO.getContent();
        CallCommunicateDTO callCommunicateDTO = packCallCommunicate(corpid, userId, userName, userAvatar,
                customerId, customerName, addCommunicateDTO.getStartTime(), memo, contactId, contactName,
                addCommunicateDTO.getRefType(), clueId, clueName);
        List<Long> dataIdList = addCommunicateDTO.getDataIdList();
        callCommunicateDTO.setDynamicMemo(addCommunicateDTO.getDynamicContent());
        customerCommunicateService.addCallCommunicate(callCommunicateDTO,dataIdList,addCommunicateDTO.getIsAuto());
        addCommunicateVO.setResult(result);
        addCommunicateVO.setCode(1);
        return addCommunicateVO;
    }

    @Override
    public TimeFilterResultVO getTimeFilterResult(AliyunCallTimeFilterResultReqDTO reqDTO) throws XbbException {
        TimeFilterResultVO timeFilterResultVO = new TimeFilterResultVO();

        String corpid = reqDTO.getCorpid();
        FiscalYearTimePojo timeFilter = reqDTO.getTimeFilter();
        if(timeFilter == null){
            timeFilter = new FiscalYearTimePojo();
        }
        //财年开始月份   设置默认为1  其实需要去查公司配置fiscalYear
        int startMonth = 1;
        timeFilter.setStartMonth(startMonth);
        Integer timeType = timeFilter.getTimeType4DefaultMonth();
        TimeTypeEnum timeTypeEnum = TimeTypeEnum.getByCode(timeType);
        if (timeTypeEnum == null) {
            timeType = TimeTypeEnum.MONTH.getCode();
        }
        timeFilter.setTimeTypeEnum(timeTypeEnum);
        Integer startTime = FiscalYearHelp.getStartTime(timeFilter, timeType, startMonth);
        Integer endTime = FiscalYearHelp.getEndTime(timeFilter, startTime, timeType, startMonth);
        timeFilterResultVO.setStartTime(startTime);
        timeFilterResultVO.setEndTime(endTime);
        return timeFilterResultVO;
    }

    @Override
    public IsActiveAliyunCallVO isActiveAliyunCall(String corpid, String userId) throws XbbException {
        return callCenterService.isActiveAliyunCall(corpid, userId);
    }

    @Override
    public XbbResponse<CompanyEntity> getCompany(AliyunCallGetCompanyReqDTO aliyunCallGetCompanyReqDTO) throws XbbException {
        String corpid = aliyunCallGetCompanyReqDTO.getCorpid();
        CompanyEntity companyEntity = companyModel.getByKeyIgnoreDel(corpid);
        return new XbbResponse<>(companyEntity);
    }

    @Override
    public PaasAppMenuVO getMenuList(String platform, int role, Integer facilitators) throws XbbException {
        PaasAppMenuVO parent = new PaasAppMenuVO();
        CloudCodeChartEnum aliyunCenter = CloudCodeChartEnum.getParentByType("AliyunCenter", platform, facilitators);
        if (Objects.isNull(aliyunCenter)) {
            return null;
        }
        parent.setId(DateUtil.getLong());
        parent.setAlias(aliyunCenter.getAlias());
        parent.setName(aliyunCenter.getName());
        parent.setIcon(aliyunCenter.getIcon());
        List<AppMenuListVO> subMenuList = new ArrayList<>();
        parent.setSubMenuList(subMenuList);
        List<CloudCodeChartEnum> childEnums = CloudCodeChartEnum.getChildListByType("AliyunCenter", platform, facilitators);
        boolean isMenu = false;
        Random rand = new Random();
        for(CloudCodeChartEnum tempEnum:childEnums){
            if(!tempEnum.getPlatform().equals(platform)&&!tempEnum.getPlatform().equals(PlatFormEnum.ALL.getValue())){
                continue;
            }
            if (!getAuth(role, tempEnum.getRoles())){
                continue;
            }
            isMenu = true;
            AppMenuListVO child = new AppMenuListVO();
            child.setId((long) child.hashCode());
            child.setName(tempEnum.getName());
            child.setAlias(tempEnum.getAlias());
            String url = proBaseConfig.getAliyunCallcenterChartUrl();
            child.setIcon(tempEnum.getIcon());
            child.setColor(tempEnum.getColor());
            parent.getSubMenuList().add(child);
            Map valueMap = new HashMap();
            valueMap.put("mobileLinkAppId",url+tempEnum.getMobileUrl());
            valueMap.put("pcLinkAppId",url+tempEnum.getUrl());
            Map actionsMap = new HashMap();
            actionsMap.put("value",valueMap);
            actionsMap.put("type","openMenuQianKun");
            Map map  = new HashMap();
            map.put("actions",actionsMap);
            map.put("pcActions",new ArrayList<>());
            map.put("mobileActions",new ArrayList<>());
            Map keyMap = new HashMap();
            keyMap.put("key","value");
            map.put("diy_params",keyMap);

            String s = JSONObject.toJSONString(map);
//            String substring = s.replace("\"","\\\"");
            child.setActions(s);

        }
        return isMenu ? parent : null;
    }

    @Override
    public ControlCenterMenuVO getManagementCenterMenuList(String platform, int role, Integer facilitators) throws XbbException {
        ControlCenterMenuVO parent = new ControlCenterMenuVO();
        CloudCodeChartEnum aliyunCenter = CloudCodeChartEnum.getParentByType("managementCenter", platform, facilitators);
        if (Objects.isNull(aliyunCenter)) {
            return null;
        }
        parent.setName(aliyunCenter.getName());
        parent.setIcon(aliyunCenter.getIcon());
        parent.setUrl("");
        parent.setType(MenuTypeEnum.APP.getType());
        List<PaasAppMenuVO> subMenuList = new ArrayList<>();
        parent.setSubMenuList(subMenuList);
        List<CloudCodeChartEnum> childEnums = CloudCodeChartEnum.getChildListByType("managementCenter", platform, facilitators);
        boolean isMenu = false;
        for(CloudCodeChartEnum tempEnum:childEnums){
            if(!tempEnum.getPlatform().equals(platform)&&!tempEnum.getPlatform().equals(PlatFormEnum.ALL.getValue())){
                continue;
            }
            if (!getAuth(role, tempEnum.getRoles())){
                continue;
            }
            isMenu = true;
            PaasAppMenuVO child = new PaasAppMenuVO();
            child.setName(tempEnum.getName());
            child.setAlias(tempEnum.getAlias());
            String url = proBaseConfig.getAliyunCallcenterChartUrl();
            child.setIcon(tempEnum.getIcon());
            child.setColor(tempEnum.getColor());
            parent.getSubMenuList().add(child);
            Map<String, Object> valueMap = new HashMap<>();
            valueMap.put("mobileLinkAppId",url+tempEnum.getMobileUrl());
            valueMap.put("pcLinkAppId",url+tempEnum.getUrl());
            Map<String, Object> actionsMap = new HashMap<>();
            actionsMap.put("value",valueMap);
            actionsMap.put("type","openMenuQianKun");
            Map<String, Object> map  = new HashMap<>();
            map.put("actions",actionsMap);
            map.put("pcActions",new ArrayList<>());
            map.put("mobileActions",new ArrayList<>());
            Map<String, Object> keyMap = new HashMap<>();
            keyMap.put("key","value");
            map.put("diy_params",keyMap);
            String actions = JSONObject.toJSONString(map);
            child.setActions(actions);

        }
        return isMenu ? parent : null;
    }

    @Override
    public GetSysVisibleVO getSysVisible(GetSysVisibleDTO getSysVisibleDTO) throws XbbException {
        GetSysVisibleVO res = new GetSysVisibleVO();
        String anotherPhoneNum = getSysVisibleDTO.getAnotherPhoneNum();
        Boolean visibleh = callCenterCallLogService.getNumberVisibleh(anotherPhoneNum, getSysVisibleDTO);
        res.setVisible(visibleh);
        return res;
    }

    /**
     * 获取权限
     *
     * @param role  角色
     * @param roles 符合的角色
     * @return true -> 有当前菜单的权限, fasle -> 没有当前菜单的权限
     */
    private boolean getAuth(Integer role, Integer[] roles){
        if(roles == null || roles.length == 0){
            return true;
        }
        for (Integer integer : roles) {
            if(integer.equals(role)){
                return true;
            }
        }
        return false;
    }
    /**
     * 捕获公司部门的层级不符的异常
     *
     * @param rootDepIdStr       跟部门的id，两边加上"|"
     * @param treeDepartmentList 部门队列
     * @param moduleType         话务中心平台
     * @throws XbbException 异常
     * @author 章华隽
     * 创建时间：2018/1/9 下午4:31
     * 修改时间：
     * @version
     * @since 3.16
     */
    private boolean catchDepartmentTreeSizeException(String rootDepIdStr, List<DepartmentEntity> treeDepartmentList, Integer moduleType)
            throws XbbException {
        if (!checkDepartmentRouter(moduleType, rootDepIdStr, treeDepartmentList)) {
            // 校验组织架构的层级是否超过
            if (Objects.equals(moduleType, CallCenterTypeEnum.CALL_CENTER_DU_YAN.getCode())) {
                throw new XbbException(DuYanErrorCodeEnum.API_ERROR_302004);
            } else if (Objects.equals(moduleType, CallCenterTypeEnum.CALL_CENTER_XBB.getCode())) {
                throw new XbbException(DuYanErrorCodeEnum.API_ERROR_302006);
            } else {
                throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301006);
            }
        }
        return true;
    }

    /**
     * 跟进记录数据封装
     *
     * @param corpid       公司ID
     * @param userId       用户ID
     * @param userName     用户姓名
     * @param userAvatar   用户Avatar
     * @param customerId   客户ID
     * @param customerName 客户姓名
     * @param startTime    开始时间
     * @param memo         备注
     * @param contactId    联系人ID
     * @param contactName  联系人姓名
     * @return
     */
    private CallCommunicateDTO packCallCommunicate(String corpid, String userId, String userName, String userAvatar,
                                                   Long customerId, String customerName, Integer startTime, String memo,
                                                   Long contactId, String contactName, Integer refType, Long clueId, String clueName) {
        CallCommunicateDTO callCommunicateDTO = new CallCommunicateDTO();
        callCommunicateDTO.setCorpid(corpid);
        callCommunicateDTO.setUserId(userId);
        callCommunicateDTO.setUserName(userName);
        callCommunicateDTO.setUserAvatar(userAvatar);
        callCommunicateDTO.setCustomerId(customerId);
        callCommunicateDTO.setCustomerName(customerName);
        callCommunicateDTO.setStartTime(startTime);
        callCommunicateDTO.setMemo(memo);
        callCommunicateDTO.setContactId(contactId);
        callCommunicateDTO.setContactName(contactName);
        callCommunicateDTO.setRefType(refType);
        callCommunicateDTO.setClueId(clueId);
        callCommunicateDTO.setClueName(clueName);
        return callCommunicateDTO;
    }

    /**
     * 销帮帮呼叫中心跳过手机号验证
     *
     * @param logUser                     登录信息
     * @param moduleType                  3602：度言  3605：销帮帮
     * @param callCenterAccountUserInfoVO 话务中心平台账户信息
     * @param corpId                      用户一键登录公司ID入参
     * @return
     * @throws XbbException
     */
    private CallCenterLoginVO checkDuYan(UserEntity logUser, Integer moduleType,
                                         CallCenterAccountUserInfoVO callCenterAccountUserInfoVO,
                                         String corpId) throws XbbException {
        CallCenterLoginVO callCenterLoginVO = new CallCenterLoginVO();
        // TODO 后期和前端联调时确定一下这个mobile参数有没有用，考虑去掉
        if (StringUtil.isEmpty(callCenterAccountUserInfoVO.getMobile())) {
            if (StringUtil.isNotEmpty(logUser.getMobile())) {
                callCenterLoginVO.setMobile(logUser.getMobile());
            }
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301003);
        } else {
            if (Objects.equals(callCenterAccountUserInfoVO.getIsMobileVerified(), 0)) {
                // 未验证手机号，等于没注册
                if (StringUtil.isNotEmpty(callCenterAccountUserInfoVO.getMobile())) {
                    callCenterLoginVO.setMobile(callCenterAccountUserInfoVO.getMobile());
                } else if (StringUtil.isNotEmpty(logUser.getMobile())) {
                    callCenterLoginVO.setMobile(logUser.getMobile());
                }
                throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301003);
            } else {
                String apiKey = callCenterOrganizationService.getApiKey(corpId, moduleType);
                // 未获取token 或 已过期
                getToken(callCenterAccountUserInfoVO, apiKey);
            }
        }
        return callCenterLoginVO;
    }

    /**
     * 未获取token 或 已过期
     *
     * @param callCenterAccountUserInfoVO 根据销帮帮CRM的用户信息获取话务中心的平台账号回参
     * @param apiKey                      三方维护apiKey
     * @return String
     * @throws XbbException
     */
    private void getToken(CallCenterAccountUserInfoVO callCenterAccountUserInfoVO, String apiKey) throws XbbException {
        String token;
        try {
            CallCenterAccountEntity callCenterAccountEntity = new CallCenterAccountEntity();
            BeanUtils.copyProperties(callCenterAccountUserInfoVO, callCenterAccountEntity);
            token = getAccountToken(apiKey, callCenterAccountEntity);
        } catch (XbbException e) {
            LOG.error(e.getMessage());
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018);
        }
        if (StringUtil.isEmpty(token)) {
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301004);
        }
    }


    /**
     * 封装要返回给前端的用户登录话务中心使用的数据
     *
     * @param loginVO 封装的载体
     * @param infoVO  用户的话务中心账号
     * @author youli.chen
     * 创建时间：2019/2/12 下午13:14
     * @version v1.0
     * @since v1.0
     */
    private void initCallCenterAccountInfo(CallCenterLoginVO loginVO, CallCenterAccountUserInfoVO infoVO) throws XbbException {
        loginVO.setMobile(infoVO.getMobile());
        loginVO.setToken(infoVO.getToken());
        loginVO.setAccountId(infoVO.getAccountId());
        loginVO.setIsAgent(infoVO.getIsAgent());
        loginVO.setIsSupervisor(infoVO.getIsSupervisor());
        loginVO.setIsAdmin(infoVO.getIsAdmin());

        XbbResponse<CallCenterConfigVO> configResponse = callCenterConfigService.getByCorpId(infoVO.getCorpid(), infoVO.getModuleType());
        CallCenterConfigVO callCenterConfigVO = configResponse.getResult();
        if (callCenterConfigVO != null) {
            loginVO.setIsAutoOpenDetail(callCenterConfigVO.getIsAutoOpenDetail());
        }

        if (infoVO.getModuleType().equals(CallCenterTypeEnum.CALL_CENTER_DU_YAN.getCode())) {
            // 超管用于登录CFG
            if (Objects.equals(infoVO.getIsAdmin(), 1)) {
                // 获取 admin 的Token
                String adminToken = getAdminToken(infoVO.getCorpid(), infoVO.getModuleType(), infoVO.getAccountId());
                if (StringUtil.isNotEmpty(adminToken)) {
                    loginVO.setAdminToken(adminToken);
                }
            }
            CallCenterAccountEntity callCenterAccountEntity = callCenterAccountModel.getByKey(infoVO.getId(), infoVO.getCorpid());
            loginVO.setToken(callCenterAccountEntity.getToken());
        } else {
            //超管用于登录CFG 销帮帮呼叫中心 youli.chen
            loginVO.setAdminToken(String.valueOf(CallCenterTypeEnum.CALL_CENTER_XBB.getCode()));
        }
    }

    /**
     * 通过度言获取呼出线路
     *
     * @param userInfoDTO 呼叫中心账户信息
     * @param target      呼叫号码
     * @return
     * @throws XbbException
     */
    public String registerMobileTarget(CallCenterAccountUserInfoDTO userInfoDTO, String target) throws XbbException {
        CallCenterAccountUserInfoVO userInfoVO = callCenterAccountService.getByXbbUserInfo(userInfoDTO);
        if (userInfoVO == null) {
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301003);
        } else if (!Objects.equals(userInfoVO.getIsAgent(), 1)) {
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301002);
        } else if (StringUtil.isEmpty(userInfoVO.getAccountId()) || Objects.equals(userInfoVO.getIsMobileVerified(), 0)) {
            throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301019);
        }
        Integer moduleType = userInfoDTO.getModuleType();
        CallCenterTypeEnum callCenterTypeEnum = CallCenterTypeEnum.getByCode(moduleType);
        switch (callCenterTypeEnum) {
            case CALL_CENTER_DU_YAN:
                String apiKey = callCenterOrganizationService.getApiKey(userInfoDTO.getCorpid(), moduleType);
                return duYanHttpService.registerMobileCallPhoneNum(apiKey, userInfoVO.getAccountId(), target);
            default:
                return null;
        }
    }

    @Override
    public String getAccountToken(String apiKey, final CallCenterAccountEntity callCenterAccountEntity) throws XbbException {
        if (Objects.equals(callCenterAccountEntity.getModuleType(), CallCenterTypeEnum.CALL_CENTER_DU_YAN.getCode())) {
            String token;
            // token已经过期，重新获取
            token = duYanHttpService.accountLogin(apiKey, callCenterAccountEntity.getAccountId());
            if (StringUtil.isEmpty(token)) {
                throw new XbbException(CallCenterErrorCodeEnum.API_ERROR_301064);
            }
            // 更新账户信息
            callCenterAccountEntity.setToken(token);
            callCenterAccountEntity.setGetTokenTime(DateUtil.getInt());
            callCenterAccountModel.update(callCenterAccountEntity);
            return token;
        } else {
            return null;
        }
    }

    /**
     * 获取开启的话务中心平台（一家公司只能开启一个平台）
     *
     * @param callCenterModuleDTO 获取开启的话务中心平台入参
     * @return CallCenterModuleVO
     * @throws XbbException 业务异常
     */
    @Override
    public CallCenterModuleVO module(CallCenterModuleDTO callCenterModuleDTO) throws XbbException {
        return callCenterService.module(callCenterModuleDTO.getCorpid(), callCenterModuleDTO.getUserId());
    }

    /**
     * 更换呼叫中心（一家公司只能使用一个平台）
     *
     * @param callUpdateModuleDTO 更换呼叫中心入参
     * @return CallUpdateModuleVO
     * @throws XbbException 业务异常
     */
    @Override
    public XbbResponse<CallUpdateModuleVO> updateModuleType(CallUpdateModuleDTO callUpdateModuleDTO) throws XbbException {
        CallUpdateModuleVO callUpdateModuleVO = new CallUpdateModuleVO();
        Integer moduleType = callUpdateModuleDTO.getModuleType();
        paasRedisHelper.setValue(CallCenterConstant.REDIS_KEY_ACTIVE_MODULE_TYPE,
                callUpdateModuleDTO.getCorpid() + "_" + callUpdateModuleDTO.getUserId(), moduleType, null);
        callUpdateModuleVO.setModuleType(moduleType);
        // TODO 暂时不考虑套餐应用的有效期问题（套餐中心）
        return new XbbResponse<>(callUpdateModuleVO);
    }

    /**
     * 根据呼叫手机号查找对象
     *
     * @param callFindRefDTO 根据呼叫手机号查找对象入参
     * @return CallFindRefVO
     * @throws XbbException 业务异常
     */
    @Override
    public XbbResponse<CallFindRefVO> findRef(CallFindRefDTO callFindRefDTO) throws XbbException {
        String corpid = callFindRefDTO.getCorpid();
        CallFindRefVO callFindRefVO = new CallFindRefVO();
        String refMobile = formatPhoneNum(callFindRefDTO.getMobile());

        CustomerEntityExt customerEntityExt = customerModel.getByPhone(corpid, refMobile);
        ContactEntityExt contactEntityExt = contactModel.getByPhone(corpid, refMobile);
        ClueEntityExt clueEntityExt = clueModel.getByPhone(corpid, refMobile);

        CallLogExplainPojo entity = new CallLogExplainPojo();

        // 当前登陆人有权限的客户表单模版
        List<PaasFormEntityExt> paasFormEntityExtList = paasFormService.getEnableCustomerFormList(callFindRefDTO.getLoginUser());
        if (paasFormEntityExtList.isEmpty()){
            throw new XbbException(ClueErrorCodeEnum.API_ERROR_1110013);
        }
        // 客户的第一个表单模版
        PaasFormEntityExt entityExt = paasFormEntityExtList.get(0);
        entity.setMenuId(entityExt.getMenuId());
        entity.setFormId(entityExt.getId());
        entity.setAppId(entityExt.getAppId());

        entity.setSaasMark(SaasMarkEnum.SAAS.getCode());
        entity.setBusinessType(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode());

        // 陌生号码归属于客户
        if (customerEntityExt == null && contactEntityExt == null && clueEntityExt == null) {
            // 新建，默认新建全部客户
            entity.setSubBusinessType(XbbRefTypeEnum.CUSTOMER.getCode());

            callFindRefVO.setRefType(XbbRefTypeEnum.UNKNOWN.getCode());
            callFindRefVO.setRefId(0L);
            callFindRefVO.setRefName(String.format(I18nMessageUtil.getMessage(I18nStringConstant.STRANGE_NUMBER) + "【%s】", refMobile));
            callFindRefVO.setRefMobile(refMobile);
            callFindRefVO.setHiddenRefMobile(refMobile);
        }

        UserVO loginUser = callFindRefDTO.getLoginUser();
        HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();
        BeanUtil.copyProperties(callFindRefDTO, handlerExplainDTO);
        handlerExplainDTO.setLoginUser(loginUser);
        handlerExplainDTO.setUserId(loginUser.getUserId());

        if (contactEntityExt != null) {
            handlerExplainDTO.setCreatorId(contactEntityExt.getCreatorId());
            handlerExplainDTO.setOwnerId(Arrays.asList(contactEntityExt.getOwnerId()));
            // 号码是否对其高级可见
            boolean attrVisible = false;
            PaasFormExplainEntity formExplainEntity = paasFormExplainModel.getByFormId(contactEntityExt.getFormId(), corpid);
            if(formExplainEntity != null){
                List<FieldAttrEntity> explainList = JSONArray.parseArray(formExplainEntity.getExplains(), FieldAttrEntity.class);
                Map<String, FieldAttrEntity> explainMap = new HashMap<>(explainList.size());
                explainList.forEach((item) -> explainMap.put(item.getAttr(), item));
                attrVisible = commonHelp.attrCanSee(ContactEnum.PHONE.getAttr(), explainMap, handlerExplainDTO);
                if(attrVisible){
                    List<? extends FieldAttrEntity> explainSubFormList = explainMap.get(ContactEnum.PHONE.getAttr()).getSubForm().getItems();
                    Map<String, FieldAttrEntity> explainSubFormMap = new HashMap<>(explainSubFormList.size());
                    explainSubFormList.forEach((item) -> explainSubFormMap.put(item.getAttr(), item));
                    boolean text2CanSee = commonHelp.attrCanSee(StringConstant.PHONE_TEL_ATTR, explainSubFormMap, handlerExplainDTO);
                    if(!text2CanSee){
                        attrVisible = false;
                    }
                }
            }

            entity.setBusinessType(XbbRefTypeEnum.CONTACT.getCode());
            entity.setSubBusinessType(XbbRefTypeEnum.CONTACT.getCode());
            entity.setAppId(contactEntityExt.getAppId());
            entity.setDataId(contactEntityExt.getId());

            String telNum = refPhoneNum(attrVisible, refMobile);
            callFindRefVO.setRefType(XbbRefTypeEnum.CONTACT.getCode());
            callFindRefVO.setRefId(contactEntityExt.getId());
            callFindRefVO.setRefName(contactEntityExt.getData().getString(ContactEnum.NAME.getAttr()));
            callFindRefVO.setCustomerId(contactEntityExt.getData().getLong(ContactEnum.CUSTOMER_NAME.getAttr()));
            callFindRefVO.setCustomerName(contactEntityExt.getData().getString(ContactEnum.CUSTOMER_NAME.getAttr()));
            callFindRefVO.setRefMobile(refMobile);
            callFindRefVO.setHiddenRefMobile(telNum);
        } else if (customerEntityExt != null) {
            handlerExplainDTO.setCreatorId(customerEntityExt.getCreatorId());
            handlerExplainDTO.setOwnerId(Arrays.asList(customerEntityExt.getOwnerId()));
            // 号码是否对其高级可见
            boolean attrVisible = false;
            PaasFormExplainEntity formExplainEntity = paasFormExplainModel.getByFormId(customerEntityExt.getFormId(), corpid);
            if(formExplainEntity != null){
                List<FieldAttrEntity> explainList = JSONArray.parseArray(formExplainEntity.getExplains(), FieldAttrEntity.class);
                Map<String, FieldAttrEntity> explainMap = new HashMap<>(explainList.size());
                explainList.forEach((item) -> explainMap.put(item.getAttr(), item));
                attrVisible = commonHelp.attrCanSee(CustomerManagementEnum.PHONE.getAttr(), explainMap, handlerExplainDTO);
                if(attrVisible){
                    List<? extends FieldAttrEntity> explainSubFormList = explainMap.get(CustomerManagementEnum.PHONE.getAttr()).getSubForm().getItems();
                    Map<String, FieldAttrEntity> explainSubFormMap = new HashMap<>(explainSubFormList.size());
                    explainSubFormList.forEach((item) -> explainSubFormMap.put(item.getAttr(), item));
                    boolean text2CanSee = commonHelp.attrCanSee(StringConstant.PHONE_TEL_ATTR, explainSubFormMap, handlerExplainDTO);
                    if(!text2CanSee){
                        attrVisible = false;
                    }
                }
            }

            String telNum = refPhoneNum(attrVisible, refMobile);
            entity.setAppId(customerEntityExt.getAppId());

            if (contactEntityExt == null) {
                entity.setDataId(customerEntityExt.getId());

                callFindRefVO.setRefType(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode());
                callFindRefVO.setRefId(customerEntityExt.getId());
                callFindRefVO.setRefName(customerEntityExt.getData().getString(CustomerManagementEnum.NAME.getAttr()));
                callFindRefVO.setRefMobile(refMobile);
                callFindRefVO.setHiddenRefMobile(telNum);
            } else {
                Long dataId = FastJsonHelper.getLongOrDefaultFromFormData(contactEntityExt.getData(), ContactEnum.CUSTOMER_NAME.getAttr(), 0L);
                entity.setDataId(dataId);
                // 联系人的关联客户隐藏字段可能没有，拿联系人关联客户的ID去查询名称比较稳妥
                CustomerEntityExt customer = customerModel.getByKey(dataId, corpid);
                String refName = customer.getData().getString(CustomerManagementEnum.NAME.getAttr());

                callFindRefVO.setRefType(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode());
                callFindRefVO.setRefId(dataId);
                callFindRefVO.setRefName(refName);
                callFindRefVO.setCustomerId(customerEntityExt.getId());
                callFindRefVO.setCustomerName(customerEntityExt.getData().getString(CustomerManagementEnum.NAME.getAttr()));
                callFindRefVO.setRefMobile(refMobile);
                callFindRefVO.setHiddenRefMobile(telNum);
            }
            entity.setSubBusinessType(XbbRefTypeEnum.CUSTOMER.getCode());
        } else if(contactEntityExt == null && customerEntityExt == null && clueEntityExt != null){
            handlerExplainDTO.setCreatorId(clueEntityExt.getCreatorId());
            handlerExplainDTO.setOwnerId(Arrays.asList(clueEntityExt.getOwnerId()));
            // 线索
            // 当前登陆人有权限的线索表单模版
            List<PaasFormEntityExt> cluePaasFormList = paasFormService.getEnableClueFormList(callFindRefDTO.getLoginUser());
            if (cluePaasFormList.isEmpty()){
                throw new XbbException(ClueErrorCodeEnum.API_ERROR_1110016);
            }
            // 线索的第一个表单模版
            PaasFormEntityExt clueExt = cluePaasFormList.get(0);
            entity.setMenuId(clueExt.getMenuId());
            entity.setFormId(clueExt.getId());
            entity.setSaasMark(SaasMarkEnum.SAAS.getCode());
            entity.setBusinessType(XbbRefTypeEnum.CLUE.getCode());

            entity.setDataId(clueEntityExt.getId());
            entity.setAppId(clueEntityExt.getAppId());
            entity.setSubBusinessType(XbbRefTypeEnum.ALL_CLUE.getCode());

            // 号码是否对其高级可见
            boolean attrVisible = false;
            PaasFormExplainEntity formExplainEntity = paasFormExplainModel.getByFormId(clueEntityExt.getFormId(), corpid);
            if(formExplainEntity != null){
                List<FieldAttrEntity> explainList = JSONArray.parseArray(formExplainEntity.getExplains(), FieldAttrEntity.class);
                Map<String, FieldAttrEntity> explainMap = new HashMap<>(explainList.size());
                explainList.forEach((item) -> explainMap.put(item.getAttr(), item));
                attrVisible = commonHelp.attrCanSee(ClueEnum.PHONE.getAttr(), explainMap, handlerExplainDTO);
                if(attrVisible){
                    List<? extends FieldAttrEntity> explainSubFormList = explainMap.get(ClueEnum.PHONE.getAttr()).getSubForm().getItems();
                    Map<String, FieldAttrEntity> explainSubFormMap = new HashMap<>(explainSubFormList.size());
                    explainSubFormList.forEach((item) -> explainSubFormMap.put(item.getAttr(), item));
                    boolean text2CanSee = commonHelp.attrCanSee(StringConstant.PHONE_TEL_ATTR, explainSubFormMap, handlerExplainDTO);
                    if(!text2CanSee){
                        attrVisible = false;
                    }
                }
            }
            String telNum = refPhoneNum(attrVisible, refMobile);

            callFindRefVO.setRefType(XbbRefTypeEnum.CLUE.getCode());
            callFindRefVO.setRefId(clueEntityExt.getId());
            callFindRefVO.setRefName(clueEntityExt.getData().getString(ClueEnum.COMPANY_NAME.getAttr()));
            callFindRefVO.setRefMobile(refMobile);
            callFindRefVO.setHiddenRefMobile(telNum);
        }
        callFindRefVO.setEntity(entity);
        return new XbbResponse<>(callFindRefVO);
    }

    /**
     * @param corpid     公司id
     * @param moduleType 第三方话务平台，参考CallCenterTypeEnum
     * @param depList    公司的所有部门
     * @throws XbbException 业务异常
     */
    private void syncDepartmentByXbb(String corpid, Integer moduleType, List<DepartmentEntity> depList) throws XbbException {
        List<CallCenterTeamEntity> syncedCallCenterTeamList = new ArrayList<>();
        if (moduleType == CallCenterTypeEnum.CALL_CENTER_XBB.getCode()) {
            for (DepartmentEntity it : depList) {
                if (callCenterTeamService.getByXbbDepInfo(corpid, it.getId(), moduleType) != null) {
                    continue;
                }
                syncedCallCenterTeamList.add(new CallCenterTeamEntity(corpid, it.getId(), it.getParentId(), it.getDepIdRouter(), moduleType));
            }
            // 同步企业的组织架构，持久化到本地数据库
            if (syncedCallCenterTeamList.size() > 0) {
                callCenterTeamModel.batchInsert(syncedCallCenterTeamList);
            }
            // 本次同步的部门
            Map<Long, CallCenterTeamEntity> syncedTeamMap = new HashMap<>(syncedCallCenterTeamList.size() * 2);
            for (CallCenterTeamEntity it : syncedCallCenterTeamList) {
                syncedTeamMap.put(it.getDepId(), it);
            }
            // 再将所有有父部门的进行更新
            for (DepartmentEntity it : depList) {
                // 该部门的父部门在本次的同步部门队列中
                CallCenterTeamEntity parentSyncedTeam;
                CallCenterTeamEntity syncedTeam = syncedTeamMap.get(it.getId());
                // 该部门的父部门在本次同步中进行了同步
                if (syncedTeamMap.containsKey(it.getParentId())) {
                    // 判断该部门是否也是本次同步
                    if (syncedTeam == null) {
                        // 该部门已经提前同步到度言，尝试从数据库获取
                        syncedTeam = callCenterTeamService.getByXbbDepInfo(corpid, it.getId(), moduleType);
                        if (syncedTeam == null) {
                            // 该部门已经被删除
                            continue;
                        }
                    }
                    // 有父级部门的先查找父级部门注册在度言方面的teamId
                    parentSyncedTeam = syncedTeamMap.get(it.getParentId());
                } else {
                    if (syncedTeam == null) {
                        continue;
                    }
                    // 该部门的父部门不在本次的同步队列中
                    parentSyncedTeam = callCenterTeamService.getByXbbDepInfo(corpid, it.getParentId(), moduleType);
                }
                if (parentSyncedTeam == null) {
                    // 该部门的父部门本次没有同步
                    continue;
                }
                if (!Objects.equals(syncedTeam.getParentId(), parentSyncedTeam.getTeamId())) {
                    // 当前部门的话务中心父部门平台与此次同步的父部门不同
                    syncedTeam.setParentDepId(it.getParentId());
                    syncedTeam.setDepIdRouter(it.getDepIdRouter());
                    syncedTeam.setParentId(parentSyncedTeam.getTeamId());
                    if (syncedTeam.getId() != null) {
                        callCenterTeamModel.update(syncedTeam);
                    }
                }
            }
        }
    }

    /**
     * 号码格式处理
     *
     * @param attrVisible 是否可见
     * @param refMobile   号码
     * @return
     */
    public String refPhoneNum(boolean attrVisible, String refMobile) {
        String telNum = null;
        if (!attrVisible) {
            if (refMobile.length() > 5) {
                telNum = refMobile.substring(0, 3) + "****" + refMobile.substring(refMobile.length() - 2, refMobile.length());
            } else {
                telNum = "*****";
            }
        } else {
            telNum = refMobile;
        }
        return telNum;
    }

    /**
     * 移动端筛选项
     * 下属员工
     *
     * @param isBoss       是否有全公司管理员权限
     * @param isAdmin      是否有该平台的管理员权限
     * @param isSupervisor 是否是团队主管
     * @param userEntity   当前登录的用户
     * @param infoVO       话务中心角色
     * @return 筛选项
     * @author 章华隽
     * 创建时间：2018/1/2 下午5:38
     * 修改时间：
     * @version
     * @since 3.15.1
     */
    private SelectPojo initSearchUserFilter(boolean isBoss, boolean isAdmin, boolean isSupervisor, UserEntity userEntity,
                                            CallCenterAccountUserInfoVO infoVO) {
        List<SelectOptionPojo> selectOptionPojoList = new ArrayList<>();
        List<Object> value = new ArrayList<>();
        selectOptionPojoList.add(new SelectOptionPojo(value, I18nMessageUtil.getMessage(I18nStringConstant.ALL_RECORDS), null));
        List<String> userIdList = new ArrayList<>();
        if (isBoss) {
            userIdList = callCenterAccountService.getAllAgentUserIdList(userEntity.getCorpid(),
                    null);
        } else if (isAdmin) {
            userIdList = callCenterAccountService.getAllAgentUserIdList(userEntity.getCorpid(),
                    infoVO.getModuleType());
        } else if (isSupervisor) {
            userIdList = callCenterAccountService.getSubAgentUserIdList(userEntity.getCorpid(),
                    infoVO.getModuleType(), infoVO.getDepId());
        }
        Map<String, String> userIdNameMap = userModel.getUserIdNameMap(userEntity.getCorpid(), userIdList);
        for (Map.Entry<String, String> entry : userIdNameMap.entrySet()) {
            List<Object> valuearr = new ArrayList<>();
            valuearr.add(entry.getKey());
            selectOptionPojoList.add(new SelectOptionPojo(valuearr, entry.getValue(), null));
        }
        return new SelectPojo("agentUserId", I18nMessageUtil.getMessage(I18nStringConstant.SELECT_AGENT), FieldTypeEnum.COMBO.getType(),
                selectOptionPojoList, "", I18nMessageUtil.getMessage(I18nStringConstant.ALL_AGENT));
    }

    /**
     * 移动端筛选项
     * 通话类型
     *
     * @return 筛选项
     * @author 章华隽
     * 创建时间：2018/1/2 下午5:38
     * 修改时间：
     * @version
     * @since 3.15.1
     */
    private SelectPojo initSearchTypeFilter() {
        List<SelectOptionPojo> selectOptionPojoList = new ArrayList<>();
        List<Object> value = new ArrayList<>();
        selectOptionPojoList.add(new SelectOptionPojo(value, I18nMessageUtil.getMessage(I18nStringConstant.ALL_CALL), null));
        List<Object> value1 = new ArrayList<>();
        value1.add(String.valueOf(CallLogTypeEnum.OUTBOUND.getCode()));
        selectOptionPojoList.add(new SelectOptionPojo(value1,
                CallLogTypeEnum.OUTBOUND.getName(), null));
        List<Object> value2 = new ArrayList<>();
        value2.add(String.valueOf(CallLogTypeEnum.INBOUND.getCode()));
        selectOptionPojoList.add(new SelectOptionPojo(value2,
                CallLogTypeEnum.INBOUND.getName(), null));
        return new SelectPojo("type", I18nMessageUtil.getMessage(I18nStringConstant.CALL_TYPE), FieldTypeEnum.COMBO.getType(),
                selectOptionPojoList, "", I18nMessageUtil.getMessage(I18nStringConstant.ALL_CALL));
    }

    /**
     * 移动端筛选项
     * 通话时间
     *
     * @return 筛选项
     * @author 章华隽
     * 创建时间：2018/1/2 下午5:38
     * 修改时间：
     * @version
     * @since 3.15.1
     */
    private SelectPojo initSearchCallTimeFilter() {
        return new SelectPojo("dateRange", I18nMessageUtil.getMessage(I18nStringConstant.CALL_TIME), FieldTypeEnum.DATETIME.getType());
    }

    /**
     * 获取用户信息
     *
     * @param userId
     * @param corpid
     * @return UserVO
     * @throws XbbException
     */
    private UserVO getUserVO(String userId, String corpid) throws XbbException {
        UserInfoDTO userInfoDTO = new UserInfoDTO();
        userInfoDTO.setCorpid(corpid);
        userInfoDTO.setUserId(userId);
        userInfoDTO.setPlatform(PlatFormEnum.INTERNAL.getValue());
        userInfoDTO.setPaasPermissionsFlag(true);
        userInfoDTO.setUserDetailFlag(true);
        userInfoDTO.setCompanyInfoFlag(false);
        UserInfoVO userInfoResp = userService.getUserInfo(userInfoDTO);
        return userInfoResp.getUser();
    }
}
